diff --git a/lib/compass/sass_extensions/sprites.rb b/lib/compass/sass_extensions/sprites.rb index 7927799e..48e2d959 100644 --- a/lib/compass/sass_extensions/sprites.rb +++ b/lib/compass/sass_extensions/sprites.rb @@ -1,4 +1,9 @@ require 'digest/md5' +#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/image' require 'compass/sass_extensions/sprites/image_row' @@ -8,7 +13,6 @@ require 'compass/sass_extensions/sprites/engines' module Compass module SassExtensions module Sprites - end end end \ No newline at end of file diff --git a/lib/compass/sass_extensions/sprites/base.rb b/lib/compass/sass_extensions/sprites/base.rb index 0ed72b24..916347b7 100644 --- a/lib/compass/sass_extensions/sprites/base.rb +++ b/lib/compass/sass_extensions/sprites/base.rb @@ -1,11 +1,14 @@ -require 'compass/sass_extensions/sprites/helpers/image_helper' -require 'compass/sass_extensions/sprites/helpers/processing_helper' 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 - include ProcessingHelper # Initialize a new aprite object from a relative file path # the path is relative to the images_path confguration option @@ -17,20 +20,7 @@ module Compass new(sprites, sprite_map, context, kwargs) end - # Loads the sprite engine - def require_engine! - self.class.send(:include, eval("::Compass::SassExtensions::Sprites::#{modulize}Engine")) - end - - # Changing this string will invalidate all previously generated sprite images. - # We should do so only when the packing algorithm changes - SPRITE_VERSION = "1" - - attr_accessor :image_names, :path, :name, :map, :kwargs - attr_accessor :images, :width, :height - - - def initialize(sprites, sprite_map, context, kwargs) + def initialize(sprites, sprite_map, context, kwargs) require_engine! @image_names = sprites @path = sprite_map.path @@ -46,116 +36,10 @@ module Compass validate! compute_image_metadata! end - - - - # 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) + # Loads the sprite engine + def require_engine! + self.class.send(:include, eval("::Compass::SassExtensions::Sprites::#{modulize}Engine")) end def inspect diff --git a/lib/compass/sass_extensions/sprites/image_helper.rb b/lib/compass/sass_extensions/sprites/image_helper.rb new file mode 100644 index 00000000..e02f571e --- /dev/null +++ b/lib/compass/sass_extensions/sprites/image_helper.rb @@ -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 \ No newline at end of file diff --git a/lib/compass/sass_extensions/sprites/processing.rb b/lib/compass/sass_extensions/sprites/processing.rb new file mode 100644 index 00000000..68b64160 --- /dev/null +++ b/lib/compass/sass_extensions/sprites/processing.rb @@ -0,0 +1,34 @@ +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 + image.left = image.position.unit_str == "%" ? (@width - image.width) * (image.position.value / 100) : image.position.value + 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 \ No newline at end of file diff --git a/lib/compass/sass_extensions/sprites/sprite.rb b/lib/compass/sass_extensions/sprites/sprite.rb new file mode 100644 index 00000000..3cdf3eed --- /dev/null +++ b/lib/compass/sass_extensions/sprites/sprite.rb @@ -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 \ No newline at end of file