Compare commits
12 Commits
stable
...
better_spr
Author | SHA1 | Date | |
---|---|---|---|
|
cfd7dd3cf3 | ||
|
d1ec112b99 | ||
|
ba2b608f73 | ||
|
387bf3665a | ||
|
7794b7202f | ||
|
fc034092aa | ||
|
bf0662cf87 | ||
|
aa4999370f | ||
|
9eeff5a9fe | ||
|
370044ba77 | ||
|
cc26b98909 | ||
|
d9ca08f685 |
78
Gemfile.lock
78
Gemfile.lock
@ -1,13 +1,13 @@
|
|||||||
GIT
|
GIT
|
||||||
remote: git://github.com/johnbintz/fakefs.git
|
remote: git://github.com/johnbintz/fakefs.git
|
||||||
revision: 005ddaaeb2b2881391c31ac9846a55ce5a42c206
|
revision: 7363b6f13bfcd9f583bbf7cd1e0d65c2dc656db7
|
||||||
specs:
|
specs:
|
||||||
fakefs (0.3.1)
|
fakefs (0.3.1)
|
||||||
|
|
||||||
PATH
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
compass (0.11.1.f248c22)
|
compass (0.11.1.387bf36)
|
||||||
chunky_png (~> 1.1)
|
chunky_png (~> 1.1)
|
||||||
fssm (>= 0.2.7)
|
fssm (>= 0.2.7)
|
||||||
sass (~> 3.1)
|
sass (~> 3.1)
|
||||||
@ -17,12 +17,12 @@ GEM
|
|||||||
specs:
|
specs:
|
||||||
ZenTest (4.5.0)
|
ZenTest (4.5.0)
|
||||||
abstract (1.0.0)
|
abstract (1.0.0)
|
||||||
actionmailer (3.0.7)
|
actionmailer (3.0.9.rc3)
|
||||||
actionpack (= 3.0.7)
|
actionpack (= 3.0.9.rc3)
|
||||||
mail (~> 2.2.15)
|
mail (~> 2.2.19)
|
||||||
actionpack (3.0.7)
|
actionpack (3.0.9.rc3)
|
||||||
activemodel (= 3.0.7)
|
activemodel (= 3.0.9.rc3)
|
||||||
activesupport (= 3.0.7)
|
activesupport (= 3.0.9.rc3)
|
||||||
builder (~> 2.1.2)
|
builder (~> 2.1.2)
|
||||||
erubis (~> 2.6.6)
|
erubis (~> 2.6.6)
|
||||||
i18n (~> 0.5.0)
|
i18n (~> 0.5.0)
|
||||||
@ -30,21 +30,21 @@ GEM
|
|||||||
rack-mount (~> 0.6.14)
|
rack-mount (~> 0.6.14)
|
||||||
rack-test (~> 0.5.7)
|
rack-test (~> 0.5.7)
|
||||||
tzinfo (~> 0.3.23)
|
tzinfo (~> 0.3.23)
|
||||||
activemodel (3.0.7)
|
activemodel (3.0.9.rc3)
|
||||||
activesupport (= 3.0.7)
|
activesupport (= 3.0.9.rc3)
|
||||||
builder (~> 2.1.2)
|
builder (~> 2.1.2)
|
||||||
i18n (~> 0.5.0)
|
i18n (~> 0.5.0)
|
||||||
activerecord (3.0.7)
|
activerecord (3.0.9.rc3)
|
||||||
activemodel (= 3.0.7)
|
activemodel (= 3.0.9.rc3)
|
||||||
activesupport (= 3.0.7)
|
activesupport (= 3.0.9.rc3)
|
||||||
arel (~> 2.0.2)
|
arel (~> 2.0.10)
|
||||||
tzinfo (~> 0.3.23)
|
tzinfo (~> 0.3.23)
|
||||||
activeresource (3.0.7)
|
activeresource (3.0.9.rc3)
|
||||||
activemodel (= 3.0.7)
|
activemodel (= 3.0.9.rc3)
|
||||||
activesupport (= 3.0.7)
|
activesupport (= 3.0.9.rc3)
|
||||||
activesupport (3.0.7)
|
activesupport (3.0.9.rc3)
|
||||||
addressable (2.2.5)
|
addressable (2.2.6)
|
||||||
arel (2.0.9)
|
arel (2.0.10)
|
||||||
autotest (4.4.6)
|
autotest (4.4.6)
|
||||||
ZenTest (>= 4.4.1)
|
ZenTest (>= 4.4.1)
|
||||||
autotest-fsevent (0.2.5)
|
autotest-fsevent (0.2.5)
|
||||||
@ -61,7 +61,7 @@ GEM
|
|||||||
term-ansicolor (~> 1.0.5)
|
term-ansicolor (~> 1.0.5)
|
||||||
diff-lcs (1.1.2)
|
diff-lcs (1.1.2)
|
||||||
em-dir-watcher (0.9.4)
|
em-dir-watcher (0.9.4)
|
||||||
em-websocket (0.2.1)
|
em-websocket (0.3.0)
|
||||||
addressable (>= 2.1.1)
|
addressable (>= 2.1.1)
|
||||||
eventmachine (>= 0.12.9)
|
eventmachine (>= 0.12.9)
|
||||||
erubis (2.6.6)
|
erubis (2.6.6)
|
||||||
@ -71,14 +71,14 @@ GEM
|
|||||||
gherkin (2.2.9)
|
gherkin (2.2.9)
|
||||||
json (~> 1.4.6)
|
json (~> 1.4.6)
|
||||||
term-ansicolor (~> 1.0.5)
|
term-ansicolor (~> 1.0.5)
|
||||||
haml (3.1.1)
|
haml (3.1.2)
|
||||||
i18n (0.5.0)
|
i18n (0.5.0)
|
||||||
json (1.4.6)
|
json (1.4.6)
|
||||||
livereload (1.6)
|
livereload (1.6)
|
||||||
em-dir-watcher (>= 0.1)
|
em-dir-watcher (>= 0.1)
|
||||||
em-websocket (>= 0.1.2)
|
em-websocket (>= 0.1.2)
|
||||||
ruby-json (>= 1.1.2)
|
ruby-json (>= 1.1.2)
|
||||||
mail (2.2.17)
|
mail (2.2.19)
|
||||||
activesupport (>= 2.3.6)
|
activesupport (>= 2.3.6)
|
||||||
i18n (>= 0.4.0)
|
i18n (>= 0.4.0)
|
||||||
mime-types (~> 1.16)
|
mime-types (~> 1.16)
|
||||||
@ -86,27 +86,29 @@ GEM
|
|||||||
mime-types (1.16)
|
mime-types (1.16)
|
||||||
mocha (0.9.12)
|
mocha (0.9.12)
|
||||||
polyglot (0.3.1)
|
polyglot (0.3.1)
|
||||||
rack (1.2.2)
|
rack (1.2.3)
|
||||||
rack-mount (0.6.14)
|
rack-mount (0.6.14)
|
||||||
rack (>= 1.0.0)
|
rack (>= 1.0.0)
|
||||||
rack-test (0.5.7)
|
rack-test (0.5.7)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
rails (3.0.7)
|
rails (3.0.9.rc3)
|
||||||
actionmailer (= 3.0.7)
|
actionmailer (= 3.0.9.rc3)
|
||||||
actionpack (= 3.0.7)
|
actionpack (= 3.0.9.rc3)
|
||||||
activerecord (= 3.0.7)
|
activerecord (= 3.0.9.rc3)
|
||||||
activeresource (= 3.0.7)
|
activeresource (= 3.0.9.rc3)
|
||||||
activesupport (= 3.0.7)
|
activesupport (= 3.0.9.rc3)
|
||||||
bundler (~> 1.0)
|
bundler (~> 1.0)
|
||||||
railties (= 3.0.7)
|
railties (= 3.0.9.rc3)
|
||||||
railties (3.0.7)
|
railties (3.0.9.rc3)
|
||||||
actionpack (= 3.0.7)
|
actionpack (= 3.0.9.rc3)
|
||||||
activesupport (= 3.0.7)
|
activesupport (= 3.0.9.rc3)
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
|
rdoc (~> 3.4)
|
||||||
thor (~> 0.14.4)
|
thor (~> 0.14.4)
|
||||||
rake (0.8.7)
|
rake (0.9.2)
|
||||||
rb-fsevent (0.4.0)
|
rb-fsevent (0.4.0)
|
||||||
rcov (0.9.9)
|
rcov (0.9.9)
|
||||||
|
rdoc (3.6.1)
|
||||||
rspec (2.0.1)
|
rspec (2.0.1)
|
||||||
rspec-core (~> 2.0.1)
|
rspec-core (~> 2.0.1)
|
||||||
rspec-expectations (~> 2.0.1)
|
rspec-expectations (~> 2.0.1)
|
||||||
@ -118,16 +120,16 @@ GEM
|
|||||||
rspec-core (~> 2.0.1)
|
rspec-core (~> 2.0.1)
|
||||||
rspec-expectations (~> 2.0.1)
|
rspec-expectations (~> 2.0.1)
|
||||||
ruby-json (1.1.2)
|
ruby-json (1.1.2)
|
||||||
ruby-prof (0.10.5)
|
ruby-prof (0.10.7)
|
||||||
rubyzip (0.9.4)
|
rubyzip (0.9.4)
|
||||||
sass (3.1.1)
|
sass (3.1.2)
|
||||||
sys-uname (0.8.5)
|
sys-uname (0.8.5)
|
||||||
term-ansicolor (1.0.5)
|
term-ansicolor (1.0.5)
|
||||||
thor (0.14.6)
|
thor (0.14.6)
|
||||||
timecop (0.3.5)
|
timecop (0.3.5)
|
||||||
treetop (1.4.9)
|
treetop (1.4.9)
|
||||||
polyglot (>= 0.3.1)
|
polyglot (>= 0.3.1)
|
||||||
tzinfo (0.3.26)
|
tzinfo (0.3.27)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
ruby
|
ruby
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
require 'digest/md5'
|
require 'digest/md5'
|
||||||
require 'compass/sprite_importer'
|
require 'compass/sprite_importer'
|
||||||
|
|
||||||
|
|
||||||
module Compass
|
module Compass
|
||||||
module SassExtensions
|
module SassExtensions
|
||||||
module Sprites
|
module Sprites
|
||||||
@ -8,7 +9,13 @@ module Compass
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'compass/sass_extensions/sprites/image'
|
#modules
|
||||||
|
require 'compass/sass_extensions/sprites/sprite'
|
||||||
|
require 'compass/sass_extensions/sprites/processing'
|
||||||
|
require 'compass/sass_extensions/sprites/image_helper'
|
||||||
|
#classes
|
||||||
require 'compass/sass_extensions/sprites/sprite_map'
|
require 'compass/sass_extensions/sprites/sprite_map'
|
||||||
require 'compass/sass_extensions/sprites/engines'
|
require 'compass/sass_extensions/sprites/image'
|
||||||
|
require 'compass/sass_extensions/sprites/row_fitter'
|
||||||
|
require 'compass/sass_extensions/sprites/image_row'
|
||||||
|
require 'compass/sass_extensions/sprites/engines'
|
74
lib/compass/sass_extensions/sprites/base.rb
Normal file
74
lib/compass/sass_extensions/sprites/base.rb
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
module Compass
|
||||||
|
module SassExtensions
|
||||||
|
module Sprites
|
||||||
|
class Base < Sass::Script::Literal
|
||||||
|
|
||||||
|
attr_accessor :image_names, :path, :name, :map, :kwargs
|
||||||
|
attr_accessor :images, :width, :height
|
||||||
|
|
||||||
|
include Sprite
|
||||||
|
include Processing
|
||||||
|
include ImageHelper
|
||||||
|
|
||||||
|
# Initialize a new aprite object from a relative file path
|
||||||
|
# the path is relative to the <tt>images_path</tt> confguration option
|
||||||
|
def self.from_uri(uri, context, kwargs)
|
||||||
|
sprite_map = ::Compass::SpriteMap.new(:uri => uri.value, :options => {})
|
||||||
|
sprites = sprite_map.files.map do |sprite|
|
||||||
|
sprite.gsub(Compass.configuration.images_path+"/", "")
|
||||||
|
end
|
||||||
|
new(sprites, sprite_map, context, kwargs)
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(sprites, sprite_map, context, kwargs)
|
||||||
|
require_engine!
|
||||||
|
@image_names = sprites
|
||||||
|
@path = sprite_map.path
|
||||||
|
@name = sprite_map.name
|
||||||
|
@kwargs = kwargs
|
||||||
|
@kwargs['cleanup'] ||= Sass::Script::Bool.new(true)
|
||||||
|
@kwargs['smart_pack'] ||= Sass::Script::Bool.new(false)
|
||||||
|
@images = nil
|
||||||
|
@width = nil
|
||||||
|
@height = nil
|
||||||
|
@evaluation_context = context
|
||||||
|
@map = sprite_map
|
||||||
|
validate!
|
||||||
|
compute_image_metadata!
|
||||||
|
end
|
||||||
|
|
||||||
|
# Loads the sprite engine
|
||||||
|
def require_engine!
|
||||||
|
self.class.send(:include, eval("::Compass::SassExtensions::Sprites::#{modulize}Engine"))
|
||||||
|
end
|
||||||
|
|
||||||
|
def inspect
|
||||||
|
to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s(kwargs = self.kwargs)
|
||||||
|
sprite_url(self).value
|
||||||
|
end
|
||||||
|
|
||||||
|
def respond_to?(meth)
|
||||||
|
super || @evaluation_context.respond_to?(meth)
|
||||||
|
end
|
||||||
|
|
||||||
|
def method_missing(meth, *args, &block)
|
||||||
|
if @evaluation_context.respond_to?(meth)
|
||||||
|
@evaluation_context.send(meth, *args, &block)
|
||||||
|
else
|
||||||
|
super
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def modulize
|
||||||
|
@modulize ||= Compass::configuration.sprite_engine.to_s.scan(/([^_.]+)/).flatten.map {|chunk| "#{chunk[0].chr.upcase}#{chunk[1..-1]}" }.join
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -107,7 +107,10 @@ module Compass
|
|||||||
base.image_for($1)
|
base.image_for($1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def <=>(other)
|
||||||
|
other.width <=> self.width
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def dimensions
|
def dimensions
|
||||||
|
32
lib/compass/sass_extensions/sprites/image_helper.rb
Normal file
32
lib/compass/sass_extensions/sprites/image_helper.rb
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
module Compass
|
||||||
|
module SassExtensions
|
||||||
|
module Sprites
|
||||||
|
module ImageHelper
|
||||||
|
# Fetches the Sprite::Image object for the supplied name
|
||||||
|
def image_for(name)
|
||||||
|
@images.detect { |img| img.name == name}
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns true if the image name has a hover selector image
|
||||||
|
def has_hover?(name)
|
||||||
|
!image_for("#{name}_hover").nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns true if the image name has a target selector image
|
||||||
|
def has_target?(name)
|
||||||
|
!image_for("#{name}_target").nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns true if the image name has an active selector image
|
||||||
|
def has_active?(name)
|
||||||
|
!image_for("#{name}_active").nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return and array of image names that make up this sprite
|
||||||
|
def sprite_names
|
||||||
|
image_names.map { |f| File.basename(f, '.png') }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
48
lib/compass/sass_extensions/sprites/image_row.rb
Normal file
48
lib/compass/sass_extensions/sprites/image_row.rb
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
require 'forwardable'
|
||||||
|
|
||||||
|
module Compass
|
||||||
|
module SassExtensions
|
||||||
|
module Sprites
|
||||||
|
class ImageRow
|
||||||
|
extend Forwardable
|
||||||
|
|
||||||
|
attr_reader :images, :max_width
|
||||||
|
def_delegators :@images, :last, :delete, :empty?, :length
|
||||||
|
|
||||||
|
def initialize(max_width)
|
||||||
|
@images = []
|
||||||
|
@max_width = max_width
|
||||||
|
end
|
||||||
|
|
||||||
|
def add(image)
|
||||||
|
return false if !will_fit?(image)
|
||||||
|
@images << image
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
alias :<< :add
|
||||||
|
|
||||||
|
def height
|
||||||
|
images.map(&:height).max
|
||||||
|
end
|
||||||
|
|
||||||
|
def width
|
||||||
|
images.map(&:width).max
|
||||||
|
end
|
||||||
|
|
||||||
|
def total_width
|
||||||
|
images.inject(0) {|sum, img| sum + img.width }
|
||||||
|
end
|
||||||
|
|
||||||
|
def efficiency
|
||||||
|
1 - (total_width.to_f / max_width.to_f)
|
||||||
|
end
|
||||||
|
|
||||||
|
def will_fit?(image)
|
||||||
|
(total_width + image.width) <= max_width
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
32
lib/compass/sass_extensions/sprites/processing.rb
Normal file
32
lib/compass/sass_extensions/sprites/processing.rb
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
module Compass
|
||||||
|
module SassExtensions
|
||||||
|
module Sprites
|
||||||
|
module Processing
|
||||||
|
def smart_packing
|
||||||
|
fitter = ::Compass::SassExtensions::Sprites::RowFitter.new(@images)
|
||||||
|
current_y = 0
|
||||||
|
fitter.fit!.each do |row|
|
||||||
|
current_x = 0
|
||||||
|
row.images.each_with_index do |image, index|
|
||||||
|
image.left = current_x
|
||||||
|
image.top = current_y
|
||||||
|
current_x += image.width
|
||||||
|
end
|
||||||
|
current_y += row.height
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def legacy_packing
|
||||||
|
@images.each_with_index do |image, index|
|
||||||
|
image.left = image.position.unit_str == "%" ? (@width - image.width) * (image.position.value / 100) : image.position.value
|
||||||
|
next if index == 0
|
||||||
|
last_image = @images[index-1]
|
||||||
|
image.top = last_image.top + last_image.height + [image.spacing, last_image.spacing].max
|
||||||
|
last_image = image
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
83
lib/compass/sass_extensions/sprites/row_fitter.rb
Normal file
83
lib/compass/sass_extensions/sprites/row_fitter.rb
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
require 'forwardable'
|
||||||
|
|
||||||
|
module Compass
|
||||||
|
module SassExtensions
|
||||||
|
module Sprites
|
||||||
|
class RowFitter
|
||||||
|
extend Forwardable
|
||||||
|
|
||||||
|
attr_reader :images, :rows
|
||||||
|
def_delegators :rows, :[]
|
||||||
|
|
||||||
|
def initialize(images)
|
||||||
|
@images = images.sort
|
||||||
|
@rows = []
|
||||||
|
end
|
||||||
|
|
||||||
|
def fit!(style = :scan)
|
||||||
|
send("#{style}_fit")
|
||||||
|
@rows
|
||||||
|
end
|
||||||
|
|
||||||
|
def width
|
||||||
|
@width ||= @images.collect(&:width).max
|
||||||
|
end
|
||||||
|
|
||||||
|
def efficiency
|
||||||
|
@rows.inject(0) { |sum, row| sum += row.efficiency } ** @rows.length
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def new_row(image = nil)
|
||||||
|
row = Compass::SassExtensions::Sprites::ImageRow.new(width)
|
||||||
|
row.add(image) if image
|
||||||
|
row
|
||||||
|
end
|
||||||
|
|
||||||
|
def fast_fit
|
||||||
|
row = new_row
|
||||||
|
@images.each do |image|
|
||||||
|
if !row.add(image)
|
||||||
|
@rows << row
|
||||||
|
row = new_row(image)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@rows << row
|
||||||
|
end
|
||||||
|
|
||||||
|
def scan_fit
|
||||||
|
fast_fit
|
||||||
|
|
||||||
|
moved_images = []
|
||||||
|
|
||||||
|
begin
|
||||||
|
removed = false
|
||||||
|
|
||||||
|
catch :done do
|
||||||
|
@rows.each do |row|
|
||||||
|
(@rows - [ row ]).each do |other_row|
|
||||||
|
other_row.images.each do |image|
|
||||||
|
if !moved_images.include?(image)
|
||||||
|
if row.will_fit?(image)
|
||||||
|
other_row.delete(image)
|
||||||
|
row << image
|
||||||
|
|
||||||
|
@rows.delete(other_row) if other_row.empty?
|
||||||
|
removed = true
|
||||||
|
|
||||||
|
moved_images << image
|
||||||
|
throw :done
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end while removed
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
125
lib/compass/sass_extensions/sprites/sprite.rb
Normal file
125
lib/compass/sass_extensions/sprites/sprite.rb
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
module Compass
|
||||||
|
module SassExtensions
|
||||||
|
module Sprites
|
||||||
|
module Sprite
|
||||||
|
|
||||||
|
# Changing this string will invalidate all previously generated sprite images.
|
||||||
|
# We should do so only when the packing algorithm changes
|
||||||
|
SPRITE_VERSION = "1"
|
||||||
|
|
||||||
|
# Calculates the overal image dimensions
|
||||||
|
# collects image sizes and input parameters for each sprite
|
||||||
|
# Calculates the height
|
||||||
|
def compute_image_metadata!
|
||||||
|
@width = 0
|
||||||
|
init_images
|
||||||
|
compute_image_positions!
|
||||||
|
@height = @images.last.top + @images.last.height
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates the Sprite::Image objects for each image and calculates the width
|
||||||
|
def init_images
|
||||||
|
@images = image_names.collect do |relative_file|
|
||||||
|
image = Compass::SassExtensions::Sprites::Image.new(self, relative_file, kwargs)
|
||||||
|
@width = [ @width, image.width + image.offset ].max
|
||||||
|
image
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Calculates the overal image dimensions
|
||||||
|
# collects image sizes and input parameters for each sprite
|
||||||
|
def compute_image_positions!
|
||||||
|
if kwargs.get_var('smart-pack').value
|
||||||
|
smart_packing
|
||||||
|
else
|
||||||
|
legacy_packing
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Validates that the sprite_names are valid sass
|
||||||
|
def validate!
|
||||||
|
for sprite_name in sprite_names
|
||||||
|
unless sprite_name =~ /\A#{Sass::SCSS::RX::IDENT}\Z/
|
||||||
|
raise Sass::SyntaxError, "#{sprite_name} must be a legal css identifier"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# The on-the-disk filename of the sprite
|
||||||
|
def filename
|
||||||
|
File.join(Compass.configuration.images_path, "#{path}-#{uniqueness_hash}.png")
|
||||||
|
end
|
||||||
|
|
||||||
|
# Generate a sprite image if necessary
|
||||||
|
def generate
|
||||||
|
if generation_required?
|
||||||
|
if kwargs.get_var('cleanup').value
|
||||||
|
cleanup_old_sprites
|
||||||
|
end
|
||||||
|
sprite_data = construct_sprite
|
||||||
|
save!(sprite_data)
|
||||||
|
Compass.configuration.run_callback(:sprite_generated, sprite_data)
|
||||||
|
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
|
||||||
|
def generation_required?
|
||||||
|
!File.exists?(filename) || outdated?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the uniqueness hash for this sprite object
|
||||||
|
def uniqueness_hash
|
||||||
|
@uniqueness_hash ||= begin
|
||||||
|
sum = Digest::MD5.new
|
||||||
|
sum << SPRITE_VERSION
|
||||||
|
sum << path
|
||||||
|
images.each do |image|
|
||||||
|
[:relative_file, :height, :width, :repeat, :spacing, :position, :digest].each do |attr|
|
||||||
|
sum << image.send(attr).to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
sum.hexdigest[0...10]
|
||||||
|
end
|
||||||
|
@uniqueness_hash
|
||||||
|
end
|
||||||
|
|
||||||
|
# Saves the sprite engine
|
||||||
|
def save!(output_png)
|
||||||
|
saved = output_png.save filename
|
||||||
|
Compass.configuration.run_callback(:sprite_saved, filename)
|
||||||
|
saved
|
||||||
|
end
|
||||||
|
|
||||||
|
# All the full-path filenames involved in this sprite
|
||||||
|
def image_filenames
|
||||||
|
@images.map(&:file)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Checks whether this sprite is outdated
|
||||||
|
def outdated?
|
||||||
|
if File.exists?(filename)
|
||||||
|
return @images.map(&:mtime).any? { |imtime| imtime.to_i > self.mtime.to_i }
|
||||||
|
end
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
# Mtime of the sprite file
|
||||||
|
def mtime
|
||||||
|
@mtime ||= File.mtime(filename)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Calculate the size of the sprite
|
||||||
|
def size
|
||||||
|
[width, height]
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
7
test.watchr
Normal file
7
test.watchr
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
watch('test/(.*)_test\.rb') { |m| test(m[0]) }
|
||||||
|
watch('lib/compass/sass_extensions/sprites/image_group.rb') { test('test/units/sprites/image_group_test.rb') }
|
||||||
|
watch('lib/compass/sass_extensions/sprites/row_fitter.rb') { test('test/units/sprites/row_fitter_test.rb') }
|
||||||
|
|
||||||
|
def test(file = nil)
|
||||||
|
system %{ruby -I"lib:test" #{file}}.tap { |o| puts o }
|
||||||
|
end
|
BIN
test/fixtures/sprites/public/images/image_row/large.png
vendored
Normal file
BIN
test/fixtures/sprites/public/images/image_row/large.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
test/fixtures/sprites/public/images/image_row/large_square.png
vendored
Normal file
BIN
test/fixtures/sprites/public/images/image_row/large_square.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
test/fixtures/sprites/public/images/image_row/medium.png
vendored
Normal file
BIN
test/fixtures/sprites/public/images/image_row/medium.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
BIN
test/fixtures/sprites/public/images/image_row/small.png
vendored
Normal file
BIN
test/fixtures/sprites/public/images/image_row/small.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
test/fixtures/sprites/public/images/image_row/tall.png
vendored
Normal file
BIN
test/fixtures/sprites/public/images/image_row/tall.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
@ -604,4 +604,37 @@ class SpritesTest < Test::Unit::TestCase
|
|||||||
CSS
|
CSS
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
it "should generate a sprite using smart packing" do
|
||||||
|
css = render <<-SCSS
|
||||||
|
$image_row-smart-pack: true;
|
||||||
|
@import "image_row/*.png";
|
||||||
|
@include all-image_row-sprites;
|
||||||
|
SCSS
|
||||||
|
assert_correct css, <<-CSS
|
||||||
|
.image_row-sprite, .image_row-large, .image_row-large_square, .image_row-medium, .image_row-small, .image_row-tall {
|
||||||
|
background: url('/image_row-7738758b32.png') no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image_row-large {
|
||||||
|
background-position: 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image_row-large_square {
|
||||||
|
background-position: -100px -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image_row-medium {
|
||||||
|
background-position: 0 -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image_row-small {
|
||||||
|
background-position: -140px -20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image_row-tall {
|
||||||
|
background-position: -160px -20px;
|
||||||
|
}
|
||||||
|
CSS
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
@ -21,7 +21,7 @@ require 'rubygems' if need_gems
|
|||||||
require 'compass'
|
require 'compass'
|
||||||
|
|
||||||
require 'test/unit'
|
require 'test/unit'
|
||||||
|
require 'mocha'
|
||||||
|
|
||||||
%w(command_line diff io rails test_case).each do |helper|
|
%w(command_line diff io rails test_case).each do |helper|
|
||||||
require "helpers/#{helper}"
|
require "helpers/#{helper}"
|
||||||
@ -34,4 +34,4 @@ class Test::Unit::TestCase
|
|||||||
include Compass::IoHelper
|
include Compass::IoHelper
|
||||||
extend Compass::TestCaseHelper::ClassMethods
|
extend Compass::TestCaseHelper::ClassMethods
|
||||||
|
|
||||||
end
|
end
|
||||||
|
51
test/units/sprites/image_row_test.rb
Normal file
51
test/units/sprites/image_row_test.rb
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
|
||||||
|
class ImageRowTest < Test::Unit::TestCase
|
||||||
|
|
||||||
|
def setup
|
||||||
|
@filenames = %w(large.png large_square.png medium.png tall.png small.png)
|
||||||
|
Compass.configuration.stubs(:images_path).returns('/')
|
||||||
|
@images_src_path = File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'sprites', 'public', 'images')
|
||||||
|
@image_files = Dir["#{@images_src_path}/image_row/*.png"].sort
|
||||||
|
@images = @image_files.map do |img|
|
||||||
|
Compass::SassExtensions::Sprites::Image.new(nil, img, {})
|
||||||
|
end
|
||||||
|
image_row(1000)
|
||||||
|
end
|
||||||
|
|
||||||
|
def image_row(max)
|
||||||
|
@image_row = Compass::SassExtensions::Sprites::ImageRow.new(max)
|
||||||
|
end
|
||||||
|
|
||||||
|
def populate_row
|
||||||
|
@images.each do |image|
|
||||||
|
assert @image_row.add(image)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return false if image will not fit in row" do
|
||||||
|
image_row(100)
|
||||||
|
img = Compass::SassExtensions::Sprites::Image.new(nil, File.join(@images_src_path, 'image_row', 'large.png'), {})
|
||||||
|
assert !@image_row.add(img)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should have 5 images" do
|
||||||
|
populate_row
|
||||||
|
assert_equal 5, @image_row.images.size
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return max image width" do
|
||||||
|
populate_row
|
||||||
|
assert_equal 400, @image_row.width
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return max image height" do
|
||||||
|
populate_row
|
||||||
|
assert_equal 40, @image_row.height
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should have an efficiency rating" do
|
||||||
|
populate_row
|
||||||
|
assert_equal 1 - (580.0 / 1000.0), @image_row.efficiency
|
||||||
|
end
|
||||||
|
end
|
@ -3,7 +3,6 @@ require 'mocha'
|
|||||||
require 'ostruct'
|
require 'ostruct'
|
||||||
class SpritesImageTest < Test::Unit::TestCase
|
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")
|
||||||
@ -30,6 +29,7 @@ class SpritesImageTest < Test::Unit::TestCase
|
|||||||
options.stubs(:get_var).with("#{sprite_name}-repeat").returns(::OpenStruct.new(:value => @repeat))
|
options.stubs(:get_var).with("#{sprite_name}-repeat").returns(::OpenStruct.new(:value => @repeat))
|
||||||
options.stubs(:get_var).with("#{sprite_name}-spacing").returns(::OpenStruct.new(:value => @spacing))
|
options.stubs(:get_var).with("#{sprite_name}-spacing").returns(::OpenStruct.new(:value => @spacing))
|
||||||
options.stubs(:get_var).with("#{sprite_name}-position").returns(::OpenStruct.new(:value => @position))
|
options.stubs(:get_var).with("#{sprite_name}-position").returns(::OpenStruct.new(:value => @position))
|
||||||
|
options.stubs(:get_var).with('smart_pack').returns(Sass::Script::Bool.new(false))
|
||||||
options
|
options
|
||||||
end
|
end
|
||||||
|
|
||||||
|
64
test/units/sprites/row_fitter_test.rb
Normal file
64
test/units/sprites/row_fitter_test.rb
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
require 'test_helper'
|
||||||
|
require 'compass/sass_extensions/sprites/row_fitter'
|
||||||
|
|
||||||
|
class RowFitterTest < Test::Unit::TestCase
|
||||||
|
def setup
|
||||||
|
end
|
||||||
|
|
||||||
|
def row_fitter(images = nil)
|
||||||
|
@row_fitter ||= Compass::SassExtensions::Sprites::RowFitter.new(images)
|
||||||
|
end
|
||||||
|
|
||||||
|
def teardown
|
||||||
|
@row_fitter = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_images(dims)
|
||||||
|
dims.collect { |width, height|
|
||||||
|
image = Compass::SassExtensions::Sprites::Image.new('blah', 'blah', {})
|
||||||
|
image.stubs(:width => width, :height => height)
|
||||||
|
image
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def basic_dims
|
||||||
|
[
|
||||||
|
[ 100, 10 ],
|
||||||
|
[ 80, 10 ],
|
||||||
|
[ 50, 10 ],
|
||||||
|
[ 35, 10 ],
|
||||||
|
[ 20, 10 ]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should use the fast placement algorithm' do
|
||||||
|
images = create_images(basic_dims)
|
||||||
|
|
||||||
|
row_fitter(images)
|
||||||
|
assert_equal 100, row_fitter.width
|
||||||
|
|
||||||
|
row_fitter.fit!(:fast)
|
||||||
|
|
||||||
|
assert_equal 4, row_fitter.rows.length
|
||||||
|
|
||||||
|
assert_equal [ images[0] ], row_fitter[0].images
|
||||||
|
assert_equal [ images[1] ], row_fitter[1].images
|
||||||
|
assert_equal [ images[2], images[3] ], row_fitter[2].images
|
||||||
|
assert_equal [ images[4] ], row_fitter[3].images
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should use the scan placement algorithm' do
|
||||||
|
images = create_images(basic_dims)
|
||||||
|
|
||||||
|
row_fitter(images)
|
||||||
|
|
||||||
|
row_fitter.fit!(:scan)
|
||||||
|
|
||||||
|
assert_equal 3, row_fitter.rows.length
|
||||||
|
|
||||||
|
assert_equal [ images[0] ], row_fitter[0].images
|
||||||
|
assert_equal [ images[1], images[4] ], row_fitter[1].images
|
||||||
|
assert_equal [ images[2], images[3] ], row_fitter[2].images
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -11,7 +11,7 @@ class SpriteMapTest < Test::Unit::TestCase
|
|||||||
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 = {'cleanup' => Sass::Script::Bool.new(true)}
|
@options = {'cleanup' => Sass::Script::Bool.new(true), 'smart_pack' => Sass::Script::Bool.new(false)}
|
||||||
setup_map
|
setup_map
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user