Compare commits
43 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9731c17de1 | ||
|
0954c8d59b | ||
|
610f3cdafe | ||
|
7aba64eb41 | ||
|
f209524228 | ||
|
247d6dc8e6 | ||
|
1d9e2cbc8a | ||
|
7d763f76d7 | ||
|
4603ac9900 | ||
|
5567e7b13f | ||
|
0354dd92a5 | ||
|
94fbfd9aa8 | ||
|
40d32606bb | ||
|
043d082033 | ||
|
d5fa05bc7d | ||
|
8c7223575a | ||
|
c55896b493 | ||
|
e25508f336 | ||
|
109687c7d0 | ||
|
47cec8151c | ||
|
330b39002a | ||
|
014c609118 | ||
|
df05620508 | ||
|
c0c39c53d7 | ||
|
7077b76225 | ||
|
3e7cd28635 | ||
|
53d975ffae | ||
|
acd720b41f | ||
|
6d0315ad77 | ||
|
c17fe444b6 | ||
|
c1756302ca | ||
|
fdef9d4e44 | ||
|
9380326186 | ||
|
29d39e808d | ||
|
4b75ef471e | ||
|
62157f6a7e | ||
|
6a44d58b7c | ||
|
ac85ca1e7a | ||
|
d79dea68db | ||
|
87b624a56e | ||
|
d0f33a74b9 | ||
|
a14a4f33ad | ||
|
d1708dd2c3 |
10
Gemfile
10
Gemfile
@ -1,12 +1,14 @@
|
||||
source :rubygems
|
||||
|
||||
gem "compass", :path => "."
|
||||
gem "cucumber"
|
||||
gem "rspec"
|
||||
gem "cucumber", "~> 0.9.2"
|
||||
gem "rspec", "~>2.0.0"
|
||||
gem "rails", "~>3.0.0.rc"
|
||||
gem "compass-validator", "3.0.0"
|
||||
gem "css_parser"
|
||||
gem "sass", "~> 3.1"
|
||||
gem "css_parser", "~> 1.0.1"
|
||||
gem "sass", "~> 3.1", :path => "../sass"
|
||||
gem "rcov"
|
||||
gem "rubyzip"
|
||||
gem "livereload"
|
||||
gem "chunky_png", "~> 0.10.1"
|
||||
gem "ruby-prof"
|
||||
|
14
Rakefile
14
Rakefile
@ -29,6 +29,20 @@ To run with an alternate version of Rails, make test/rails a symlink to that ver
|
||||
To run with an alternate version of Haml & Sass, make test/haml a symlink to that version.
|
||||
END
|
||||
|
||||
begin
|
||||
require 'rspec/core/rake_task'
|
||||
|
||||
RSpec::Core::RakeTask.new(:spec)
|
||||
|
||||
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
||||
spec.rcov = true
|
||||
end
|
||||
|
||||
task :default => :spec
|
||||
rescue LoadError
|
||||
puts "Rspec (or a dependency) is not available. Try running bundler install"
|
||||
end
|
||||
|
||||
desc "Compile Examples into HTML and CSS"
|
||||
task :examples do
|
||||
linked_haml = "tests/haml"
|
||||
|
19
bin/compass
19
bin/compass
@ -21,6 +21,21 @@ fallback_load_path(File.join(File.dirname(__FILE__), '..', 'lib')) do
|
||||
require 'compass/exec'
|
||||
end
|
||||
|
||||
runner = Proc.new do
|
||||
command_line_class = Compass::Exec::Helpers.select_appropriate_command_line_ui(ARGV)
|
||||
command_line_class.new(ARGV).run!
|
||||
end
|
||||
|
||||
command_line_class = Compass::Exec::Helpers.select_appropriate_command_line_ui(ARGV)
|
||||
exit command_line_class.new(ARGV).run!
|
||||
if ARGV.delete("--profile")
|
||||
require 'ruby-prof'
|
||||
RubyProf.start
|
||||
exit_code = runner.call
|
||||
result = RubyProf.stop
|
||||
|
||||
# Print a flat profile to text
|
||||
printer = RubyProf::FlatPrinter.new(result)
|
||||
printer.print(STDERR, 0)
|
||||
exit exit_code
|
||||
else
|
||||
exit runner.call
|
||||
end
|
||||
|
@ -7,7 +7,7 @@ Gem::Specification.new do |gemspec|
|
||||
gemspec.date = "#{Time.now.year}-#{Time.now.month}-#{Time.now.day}" # Automatically update for each build
|
||||
gemspec.description = "Compass is a Sass-based Stylesheet Framework that streamlines the creation and maintainance of CSS."
|
||||
gemspec.homepage = "http://compass-style.org"
|
||||
gemspec.authors = ["Chris Eppstein", "Eric A. Meyer", "Brandon Mathis"]
|
||||
gemspec.authors = ["Chris Eppstein", "Eric A. Meyer", "Brandon Mathis", "Nico Hagenburger"]
|
||||
gemspec.email = "chris@eppsteins.net"
|
||||
gemspec.default_executable = "compass"
|
||||
gemspec.executables = %w(compass)
|
||||
@ -15,7 +15,10 @@ Gem::Specification.new do |gemspec|
|
||||
gemspec.require_paths = %w(lib)
|
||||
gemspec.rubygems_version = "1.3.5"
|
||||
gemspec.summary = %q{A Real Stylesheet Framework}
|
||||
gemspec.add_dependency('sass', '~> 3.1')
|
||||
|
||||
gemspec.add_dependency 'sass', '~> 3.1'
|
||||
gemspec.add_dependency 'chunky_png', '~> 0.10.3'
|
||||
|
||||
gemspec.files = %w(README.markdown LICENSE.markdown VERSION.yml Rakefile)
|
||||
gemspec.files += Dir.glob("bin/*")
|
||||
gemspec.files += Dir.glob("examples/**/*.*")
|
||||
|
@ -9,7 +9,8 @@ gem 'fssm'
|
||||
gem 'serve', "1.0.0"
|
||||
gem 'nokogiri'
|
||||
gem 'coderay'
|
||||
gem 'haml', ">=3.0.23", :require => 'sass'
|
||||
gem 'sass', :path => "../../sass"
|
||||
gem 'haml', ">= 3.1.0.alpha.36"
|
||||
gem 'rake'
|
||||
gem 'compass', :path => ".."
|
||||
gem 'compass-susy-plugin', ">=0.7.0.pre8"
|
||||
|
@ -1,20 +1,27 @@
|
||||
GIT
|
||||
remote: git://github.com/chriseppstein/nanoc.git
|
||||
revision: 4ecb400489c83fd2068659de0c651733b8dad28f
|
||||
revision: 4eee0e60c5121b90498caa88605d416521553378
|
||||
specs:
|
||||
nanoc3 (3.2.0a3)
|
||||
cri (>= 1.0.0)
|
||||
|
||||
PATH
|
||||
remote: /Users/bmathis/Documents/Workspace/compass-projects/compass
|
||||
remote: /Users/chris/Projects/compass
|
||||
specs:
|
||||
compass (0.11.alpha.1.488fddf)
|
||||
compass (0.11.alpha.1.610f3cd)
|
||||
chunky_png (~> 0.10.3)
|
||||
sass (~> 3.1)
|
||||
|
||||
PATH
|
||||
remote: /Users/chris/Projects/sass
|
||||
specs:
|
||||
sass (3.1.0.alpha.0)
|
||||
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
activesupport (3.0.1)
|
||||
chunky_png (0.10.5)
|
||||
coderay (0.9.5)
|
||||
compass-susy-plugin (0.8.1)
|
||||
compass (>= 0.10.0)
|
||||
@ -22,7 +29,7 @@ GEM
|
||||
css-slideshow (0.2.0)
|
||||
compass (>= 0.10.0.rc3)
|
||||
fssm (0.2.0)
|
||||
haml (3.0.23)
|
||||
haml (3.1.0.alpha.36)
|
||||
i18n (0.4.2)
|
||||
json (1.4.6)
|
||||
mime-types (1.16)
|
||||
@ -30,7 +37,6 @@ GEM
|
||||
rack (1.2.1)
|
||||
rake (0.8.7)
|
||||
rdiscount (1.6.5)
|
||||
sass (3.1.0.alpha.28)
|
||||
serve (1.0.0)
|
||||
activesupport (~> 3.0.1)
|
||||
i18n (~> 0.4.1)
|
||||
@ -48,7 +54,7 @@ DEPENDENCIES
|
||||
compass-susy-plugin (>= 0.7.0.pre8)
|
||||
css-slideshow (= 0.2.0)
|
||||
fssm
|
||||
haml (>= 3.0.23)
|
||||
haml (>= 3.1.0.alpha.36)
|
||||
json
|
||||
mime-types
|
||||
nanoc3!
|
||||
@ -56,5 +62,6 @@ DEPENDENCIES
|
||||
rack
|
||||
rake
|
||||
rdiscount
|
||||
sass!
|
||||
serve (= 1.0.0)
|
||||
thor
|
||||
|
157
doc-src/assets/javascripts/shBrushSass.js
vendored
157
doc-src/assets/javascripts/shBrushSass.js
vendored
@ -7,7 +7,7 @@
|
||||
*
|
||||
* @version
|
||||
* 3.0.83 (July 02 2010)
|
||||
*
|
||||
*
|
||||
* @copyright
|
||||
* Copyright (C) 2004-2010 Alex Gorbatchev.
|
||||
*
|
||||
@ -16,59 +16,59 @@
|
||||
*/
|
||||
;(function()
|
||||
{
|
||||
// CommonJS
|
||||
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
|
||||
// CommonJS
|
||||
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
|
||||
|
||||
function Brush()
|
||||
{
|
||||
function getKeywordsCSS(str)
|
||||
{
|
||||
return '\\b([a-z_]|)' + str.replace(/ /g, '(?=:)\\b|\\b([a-z_\\*]|\\*|)') + '(?=:)\\b';
|
||||
};
|
||||
|
||||
function getValuesCSS(str)
|
||||
{
|
||||
return '\\b' + str.replace(/ /g, '(?!-)(?!:)\\b|\\b()') + '\:\\b';
|
||||
};
|
||||
function Brush()
|
||||
{
|
||||
function getKeywordsCSS(str)
|
||||
{
|
||||
return '\\b([a-z_]|)' + str.replace(/ /g, '(?=:)\\b|\\b([a-z_\\*]|\\*|)') + '(?=:)\\b';
|
||||
};
|
||||
|
||||
var keywords = 'ascent azimuth background-attachment background-color background-image background-position ' +
|
||||
'background-repeat background baseline bbox border-collapse border-color border-spacing border-style border-top ' +
|
||||
'border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color ' +
|
||||
'border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width ' +
|
||||
'border-bottom-width border-left-width border-width border bottom cap-height caption-side centerline clear clip color ' +
|
||||
'content counter-increment counter-reset cue-after cue-before cue cursor definition-src descent direction display ' +
|
||||
'elevation empty-cells float font-size-adjust font-family font-size font-stretch font-style font-variant font-weight font ' +
|
||||
'height left letter-spacing line-height list-style-image list-style-position list-style-type list-style margin-top ' +
|
||||
'margin-right margin-bottom margin-left margin marker-offset marks mathline max-height max-width min-height min-width orphans ' +
|
||||
'outline-color outline-style outline-width outline overflow padding-top padding-right padding-bottom padding-left padding page ' +
|
||||
'page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position ' +
|
||||
'quotes right richness size slope src speak-header speak-numeral speak-punctuation speak speech-rate stemh stemv stress ' +
|
||||
'table-layout text-align top text-decoration text-indent text-shadow text-transform unicode-bidi unicode-range units-per-em ' +
|
||||
'vertical-align visibility voice-family volume white-space widows width widths word-spacing x-height z-index zoom';
|
||||
|
||||
var values = 'above absolute all always aqua armenian attr aural auto avoid baseline behind below bidi-override black blink block blue bold bolder '+
|
||||
'both bottom braille capitalize caption center center-left center-right circle close-quote code collapse compact condensed '+
|
||||
'continuous counter counters crop cross crosshair cursive dashed decimal decimal-leading-zero digits disc dotted double '+
|
||||
'embed embossed e-resize expanded extra-condensed extra-expanded fantasy far-left far-right fast faster fixed format fuchsia '+
|
||||
'gray green groove handheld hebrew help hidden hide high higher icon inline-table inline inset inside invert italic '+
|
||||
'justify landscape large larger left-side left leftwards level lighter lime line-through list-item local loud lower-alpha '+
|
||||
'lowercase lower-greek lower-latin lower-roman lower low ltr marker maroon medium message-box middle mix move narrower '+
|
||||
'navy ne-resize no-close-quote none no-open-quote no-repeat normal nowrap n-resize nw-resize oblique olive once open-quote outset '+
|
||||
'outside overline pointer portrait pre print projection purple red relative repeat repeat-x repeat-y rgb ridge right right-side '+
|
||||
'rightwards rtl run-in screen scroll semi-condensed semi-expanded separate se-resize show silent silver slower slow '+
|
||||
'small small-caps small-caption smaller soft solid speech spell-out square s-resize static status-bar sub super sw-resize '+
|
||||
'table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group teal '+
|
||||
'text-bottom text-top thick thin top transparent tty tv ultra-condensed ultra-expanded underline upper-alpha uppercase upper-latin '+
|
||||
'upper-roman url visible wait white wider w-resize x-fast x-high x-large x-loud x-low x-slow x-small x-soft xx-large xx-small yellow';
|
||||
|
||||
var fonts = '[mM]onospace [tT]ahoma [vV]erdana [aA]rial [hH]elvetica [sS]ans-serif [sS]erif [cC]ourier mono sans serif';
|
||||
|
||||
var statements = '!important !default';
|
||||
var preprocessors = 'import extend debug warn if for while mixin include';
|
||||
|
||||
var r = SyntaxHighlighter.regexLib;
|
||||
|
||||
var getKeywordsPrependedBy = function(keywords, by)
|
||||
function getValuesCSS(str)
|
||||
{
|
||||
return '\\b' + str.replace(/ /g, '(?!-)(?!:)\\b|\\b()') + '\:\\b';
|
||||
};
|
||||
|
||||
var keywords = 'ascent azimuth background-attachment background-color background-image background-position ' +
|
||||
'background-repeat background baseline bbox border-collapse border-color border-spacing border-style border-top ' +
|
||||
'border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color ' +
|
||||
'border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width ' +
|
||||
'border-bottom-width border-left-width border-width border bottom cap-height caption-side centerline clear clip color ' +
|
||||
'content counter-increment counter-reset cue-after cue-before cue cursor definition-src descent direction display ' +
|
||||
'elevation empty-cells float font-size-adjust font-family font-size font-stretch font-style font-variant font-weight font ' +
|
||||
'height left letter-spacing line-height list-style-image list-style-position list-style-type list-style margin-top ' +
|
||||
'margin-right margin-bottom margin-left margin marker-offset marks mathline max-height max-width min-height min-width orphans ' +
|
||||
'outline-color outline-style outline-width outline overflow padding-top padding-right padding-bottom padding-left padding page ' +
|
||||
'page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position ' +
|
||||
'quotes right richness size slope src speak-header speak-numeral speak-punctuation speak speech-rate stemh stemv stress ' +
|
||||
'table-layout text-align top text-decoration text-indent text-shadow text-transform unicode-bidi unicode-range units-per-em ' +
|
||||
'vertical-align visibility voice-family volume white-space widows width widths word-spacing x-height z-index zoom';
|
||||
|
||||
var values = 'above absolute all always aqua armenian attr aural auto avoid baseline behind below bidi-override black blink block blue bold bolder '+
|
||||
'both bottom braille capitalize caption center center-left center-right circle close-quote code collapse compact condensed '+
|
||||
'continuous counter counters crop cross crosshair cursive dashed decimal decimal-leading-zero digits disc dotted double '+
|
||||
'embed embossed e-resize expanded extra-condensed extra-expanded fantasy far-left far-right fast faster fixed format fuchsia '+
|
||||
'gray green groove handheld hebrew help hidden hide high higher icon inline-table inline inset inside invert italic '+
|
||||
'justify landscape large larger left-side left leftwards level lighter lime line-through list-item local loud lower-alpha '+
|
||||
'lowercase lower-greek lower-latin lower-roman lower low ltr marker maroon medium message-box middle mix move narrower '+
|
||||
'navy ne-resize no-close-quote none no-open-quote no-repeat normal nowrap n-resize nw-resize oblique olive once open-quote outset '+
|
||||
'outside overline pointer portrait pre print projection purple red relative repeat repeat-x repeat-y rgb ridge right right-side '+
|
||||
'rightwards rtl run-in screen scroll semi-condensed semi-expanded separate se-resize show silent silver slower slow '+
|
||||
'small small-caps small-caption smaller soft solid speech spell-out square s-resize static status-bar sub super sw-resize '+
|
||||
'table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group teal '+
|
||||
'text-bottom text-top thick thin top transparent tty tv ultra-condensed ultra-expanded underline upper-alpha uppercase upper-latin '+
|
||||
'upper-roman url visible wait white wider w-resize x-fast x-high x-large x-loud x-low x-slow x-small x-soft xx-large xx-small yellow';
|
||||
|
||||
var fonts = '[mM]onospace [tT]ahoma [vV]erdana [aA]rial [hH]elvetica [sS]ans-serif [sS]erif [cC]ourier mono sans serif';
|
||||
|
||||
var statements = '!important !default';
|
||||
var preprocessors = 'import extend debug warn if for while mixin include';
|
||||
|
||||
var r = SyntaxHighlighter.regexLib;
|
||||
|
||||
var getKeywordsPrependedBy = function(keywords, by)
|
||||
{
|
||||
str = keywords
|
||||
.replace(/^\s+|\s+$/g, '')
|
||||
@ -79,34 +79,35 @@
|
||||
return '(?:' + str + ')\\b';
|
||||
}
|
||||
|
||||
this.regexList = [
|
||||
{ regex: r.multiLineCComments, css: 'comments' }, // multiline comments
|
||||
{ regex: r.singleLineCComments, css: 'comments' }, // singleline comments
|
||||
{ regex: r.doubleQuotedString, css: 'string' }, // double quoted strings
|
||||
{ regex: r.singleQuotedString, css: 'string' }, // single quoted strings
|
||||
{ regex: /\#[a-fA-F0-9]{3,6}/g, css: 'value' }, // html colors
|
||||
{ regex: /\b(-?\d+)(\.\d+)?(px|em|pt|\:|\%|)\b/g, css: 'value' }, // sizes
|
||||
{ regex: /(\$|!)\w+/g, css: 'variable' }, // variables
|
||||
{ regex: new RegExp(this.getKeywords(statements), 'g'), css: 'color3' }, // statements
|
||||
{ regex: new RegExp(getKeywordsPrependedBy(preprocessors, '@'), 'g'), css: 'preprocessor' }, // preprocessors
|
||||
{ regex: new RegExp('(^|\\n)\\s*=.*', 'g'), css: 'functions' }, // short mixin declarations
|
||||
{ regex: new RegExp('(^|\\n)\\s*\\+.*', 'g'), css: 'functions' }, // short mixin call
|
||||
{ regex: new RegExp('&', 'g'), css: 'keyword' }, // &
|
||||
{ regex: new RegExp('#(\\w|-|_)+', 'g'), css: 'color2' }, // ids
|
||||
{ regex: new RegExp('(\\.(\\w|-|_)+)', 'g'), css: 'color4' }, // classes
|
||||
{ regex: new RegExp(getKeywordsCSS(keywords), 'gm'), css: 'keyword' }, // keywords
|
||||
{ regex: new RegExp(getKeywordsPrependedBy(keywords, ':'), 'g'), css: 'keyword' }, // :keyword value
|
||||
{ regex: new RegExp(getValuesCSS(values), 'g'), css: 'value' }, // values
|
||||
{ regex: new RegExp(this.getKeywords(fonts), 'g'), css: 'color1' } // fonts
|
||||
];
|
||||
};
|
||||
this.regexList = [
|
||||
{ regex: r.multiLineCComments, css: 'comments' }, // multiline comments
|
||||
{ regex: r.singleLineCComments, css: 'comments' }, // singleline comments
|
||||
{ regex: r.doubleQuotedString, css: 'string' }, // double quoted strings
|
||||
{ regex: r.singleQuotedString, css: 'string' }, // single quoted strings
|
||||
{ regex: /\#[a-fA-F0-9]{3,6}/g, css: 'value' }, // html colors
|
||||
{ regex: /\b(-?\d+)(\.\d+)?(px|em|pt|\:|\%|)\b/g, css: 'value' }, // sizes
|
||||
{ regex: /(\$|!)\w+/g, css: 'variable' }, // variables
|
||||
{ regex: new RegExp(this.getKeywords(statements), 'g'), css: 'color3' }, // statements
|
||||
{ regex: new RegExp(getKeywordsPrependedBy(preprocessors, '@'), 'g'), css: 'preprocessor' }, // preprocessors
|
||||
{ regex: new RegExp('(^|\\n)\\s*=.*', 'g'), css: 'functions' }, // short mixin declarations
|
||||
{ regex: new RegExp('(^|\\n)\\s*\\+.*', 'g'), css: 'functions' }, // short mixin call
|
||||
{ regex: new RegExp('&', 'g'), css: 'keyword' }, // &
|
||||
{ regex: new RegExp('#(\\w|-|_)+', 'g'), css: 'color2' }, // ids
|
||||
{ regex: new RegExp('(\\.(\\w|-|_)+)', 'g'), css: 'color4' }, // classes
|
||||
{ regex: new RegExp(getKeywordsCSS(keywords), 'gm'), css: 'keyword' }, // keywords
|
||||
{ regex: new RegExp(getKeywordsPrependedBy(keywords, ':'), 'g'), css: 'keyword' }, // :keyword value
|
||||
{ regex: new RegExp(getValuesCSS(values), 'g'), css: 'value' }, // values
|
||||
{ regex: new RegExp(this.getKeywords(fonts), 'g'), css: 'color1' } // fonts
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
Brush.prototype = new SyntaxHighlighter.Highlighter();
|
||||
Brush.aliases = ['sass', 'scss'];
|
||||
Brush.prototype = new SyntaxHighlighter.Highlighter();
|
||||
Brush.aliases = ['sass', 'scss'];
|
||||
|
||||
SyntaxHighlighter.brushes.Sass = Brush;
|
||||
SyntaxHighlighter.brushes.Sass = Brush;
|
||||
|
||||
// CommonJS
|
||||
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
|
||||
// CommonJS
|
||||
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
|
||||
})();
|
||||
|
||||
|
3
doc-src/assets/javascripts/shCore.js
vendored
3
doc-src/assets/javascripts/shCore.js
vendored
File diff suppressed because one or more lines are too long
8
doc-src/content/help/tutorials/spriting.markdown
Normal file
8
doc-src/content/help/tutorials/spriting.markdown
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
title: Spriting with Compass
|
||||
layout: tutorial
|
||||
crumb: Spriting
|
||||
classnames:
|
||||
- tutorial
|
||||
---
|
||||
# Spriting with Compass
|
132
doc-src/content/reference/compass/helpers/sprites.haml
Normal file
132
doc-src/content/reference/compass/helpers/sprites.haml
Normal file
@ -0,0 +1,132 @@
|
||||
---
|
||||
title: Compass Sprite Helpers
|
||||
crumb: Sprites
|
||||
framework: compass
|
||||
meta_description: Helper functions for working with Sprite images.
|
||||
layout: core
|
||||
classnames:
|
||||
- reference
|
||||
- core
|
||||
- helpers
|
||||
---
|
||||
%h1 Compass Sprite Helpers
|
||||
|
||||
:markdown
|
||||
These helpers make it easier to build and to work with sprites.
|
||||
|
||||
While it is allowed to use these directly, to do so is considered "advanced usage".
|
||||
It is recommended that you instead use the sprite mixins that are designed to work
|
||||
with these functions.
|
||||
|
||||
See the [Spriting Tutorial](/help/tutorials/spriting/) for more information.
|
||||
|
||||
#sprite-map.helper
|
||||
%h3
|
||||
%a(href="#sprite-map")
|
||||
sprite-map(<span class="arg">$glob</span>, <span class="arg">...</span>)
|
||||
.details
|
||||
:markdown
|
||||
Generates a sprite map from the files matching the glob pattern. Uses the
|
||||
keyword-style arguments passed in to control the placement.
|
||||
|
||||
Only PNG files can be made into sprites at this time.
|
||||
|
||||
The `$glob` should be glob pattern relative to the images directory that specifies
|
||||
what files will be in the sprite. For example:
|
||||
|
||||
$icons: sprite-map("icons/*.png");
|
||||
background: $icons;
|
||||
|
||||
This will generate a sprite map and return a reference to it. It's important to
|
||||
capture this to a variable, because you will need to use it later when creating
|
||||
sprites. In the above example you might end up with a new file named
|
||||
`images/sprites/icons-a2ef041.png` and your css stylesheet will have:
|
||||
|
||||
background: url('/images/sprites/icons-a2ef041.png?1234678') no-repeat;
|
||||
|
||||
The exact image name is not something you should depend on as it may change based on the
|
||||
arguments you pass in. Instead, you can use the `sprite-url()` function to create a
|
||||
reference to the sprite map without generating the image again. Alternatively, simply
|
||||
using the sprite map variable in an property will have the same effect as calling
|
||||
`sprite-url()`.
|
||||
|
||||
For each sprite in the sprite map you can control the position, spacing, and whether or
|
||||
not it repeats. You do this by passing arguments to this function that tell each sprite
|
||||
how to behave. For instance if there is a icons/new.png then you can control it like so:
|
||||
|
||||
$icon-sprite: sprite-map("icons/*.png",
|
||||
$new-position: 100%, $new-spacing: 15px, $new-repeat: no-repeat);
|
||||
|
||||
If you don't specify these options they will default to `0%` for `position`,
|
||||
`0px` for spacing, and `no-repeat` for `repeat`.
|
||||
|
||||
Default values for all sprites can be specified by passing values for `$position`,
|
||||
`$spacing`, and `$repeat`.
|
||||
|
||||
#sprite.helper
|
||||
%h3
|
||||
%a(href="#sprite")
|
||||
sprite(<span class="arg">$map</span>, <span class="arg">$sprite</span>, <span class="arg" data-default-value="0">$offset-x</span>, <span class="arg" data-default-value="0">$offset-y</span>)
|
||||
.details
|
||||
:markdown
|
||||
Returns the image and background position for use in a single shorthand property:
|
||||
|
||||
$icons: sprite-map("icons/*.png"); // contains icons/new.png among others.
|
||||
background: sprite($icons, new) no-repeat;
|
||||
|
||||
Becomes:
|
||||
|
||||
background: url('/images/icons.png?12345678') 0 -24px no-repeat;
|
||||
|
||||
#sprite-map-name.helper
|
||||
%h3
|
||||
%a(href="#sprite-map-name")
|
||||
sprite-map-name(<span class="arg">$map</span>)
|
||||
.details
|
||||
:markdown
|
||||
Returns the name of a sprite map
|
||||
The name is derived from the folder than contains the sprites.
|
||||
|
||||
#sprite-file.helper
|
||||
%h3
|
||||
%a(href="#sprite-file")
|
||||
sprite-file(<span class="arg">$map</span>, <span class="arg">$sprite</span>)
|
||||
.details
|
||||
:markdown
|
||||
Returns the relative path (from the images directory) to the original file
|
||||
used when construction the sprite. This is suitable for passing to the
|
||||
`image-width` and `image-height` helpers.
|
||||
|
||||
#sprite-url.helper
|
||||
%h3
|
||||
%a(href="#sprite-url")
|
||||
sprite-url(<span class="arg">$map</span>)
|
||||
.details
|
||||
:markdown
|
||||
Returns a url to the sprite image.
|
||||
|
||||
#sprite-position.helper
|
||||
%h3
|
||||
%a(href="#sprite-position")
|
||||
sprite-position(<span class="arg">$map</span>, <span class="arg">$sprite</span>, <span class="arg" data-default-value="0">$offset-x</span>, <span class="arg" data-default-value="0">$offset-y</span>)
|
||||
.details
|
||||
:markdown
|
||||
Returns the position for the original image in the sprite.
|
||||
This is suitable for use as a value to background-position:
|
||||
|
||||
$icons: sprite-map("icons/*.png");
|
||||
background-position: sprite-position($icons, new);
|
||||
|
||||
Might generate something like:
|
||||
|
||||
background-position: 0 -34px;
|
||||
|
||||
You can adjust the background relative to this position by passing values for
|
||||
`$offset-x` and `$offset-y`:
|
||||
|
||||
$icons: sprite-map("icons/*.png");
|
||||
background-position: sprite-position($icons, new, 3px, -2px);
|
||||
|
||||
Would change the above output to:
|
||||
|
||||
background-position: 3px -36px;
|
@ -0,0 +1,18 @@
|
||||
---
|
||||
title: Compass Sprite Base
|
||||
crumb: Sprite Base
|
||||
framework: compass
|
||||
stylesheet: compass/utilities/sprites/_base.scss
|
||||
layout: core
|
||||
nav_stylesheet: compass/_utilities.scss
|
||||
classnames:
|
||||
- reference
|
||||
- core
|
||||
- utilities
|
||||
---
|
||||
- render 'reference' do
|
||||
:markdown
|
||||
These mixins are useful for working with sprites. This file is imported by
|
||||
magic sprite imports.
|
||||
|
||||
See the [Spriting Tutorial](/help/tutorials/spriting/) for more information.
|
@ -1,6 +1,6 @@
|
||||
// Default Syntax Highlighter theme.
|
||||
//@import "shCore.scss";
|
||||
//@import "shThemeRDark.scss";
|
||||
@import "shCore.scss";
|
||||
@import "shThemeRDark.scss";
|
||||
|
||||
/*.syntaxhighlighter {
|
||||
.keyword { font-weight: bold !important; }
|
||||
|
@ -156,6 +156,7 @@ Feature: Command Line
|
||||
| imports |
|
||||
| install |
|
||||
| interactive |
|
||||
| sprite |
|
||||
| stats |
|
||||
| unpack |
|
||||
| validate |
|
||||
|
38
frameworks/compass/stylesheets/_lemonade.scss
Normal file
38
frameworks/compass/stylesheets/_lemonade.scss
Normal file
@ -0,0 +1,38 @@
|
||||
@mixin image-dimensions($file) {
|
||||
height: image-height($file);
|
||||
width: image-width($file);
|
||||
}
|
||||
|
||||
@mixin sprite-image($file) {
|
||||
background: sprite-image($file) $repeat;
|
||||
}
|
||||
|
||||
@mixin sized-sprite-image($file) {
|
||||
background: sprite-image($file);
|
||||
@include image-dimensions($file);
|
||||
}
|
||||
|
||||
@mixin sprite-folder($folder, $image-dimensions: false) {
|
||||
.#{$folder} {
|
||||
@if $image-dimensions {
|
||||
background: sprite-url($folder);
|
||||
}
|
||||
@else {
|
||||
background: sprite-url($folder) no-repeat;
|
||||
}
|
||||
}
|
||||
@for $i from 0 to sprite-files-in-folder($folder) {
|
||||
$file: sprite-file-from-folder($folder, $i);
|
||||
.#{$folder}-#{image-basename($file)} {
|
||||
@extend .#{$folder};
|
||||
background-position: sprite-position(sprite-file-from-folder($folder, $i));
|
||||
@if $image-dimensions {
|
||||
@include image-dimensions($file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin sized-sprite-folder($folder) {
|
||||
@include sprite-folder($folder, true);
|
||||
}
|
@ -9,6 +9,8 @@ $default-background-size: 100% auto !default;
|
||||
// * percentages are relative to the background-origin (default = padding-box)
|
||||
// * mixin defaults to: `$default-background-size`
|
||||
@mixin background-size($size: $default-background-size) {
|
||||
$size: unquote($size);
|
||||
@if type-of($size) == string {
|
||||
$size: unquote($size);
|
||||
}
|
||||
@include experimental(background-size, $size, -moz, -webkit, -o, not -ms, not -khtml);
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
// Set the width and height of an element to the original
|
||||
// dimensions of an image before it was included in the sprite.
|
||||
@mixin sprite-dimensions($map, $sprite) {
|
||||
height: image-height(sprite-file($map, $sprite));
|
||||
width: image-width(sprite-file($map, $sprite));
|
||||
}
|
||||
|
||||
// Set the background position of the given sprite `$map` to display the
|
||||
// sprite of the given `$sprite` name. You can move the image relative to its
|
||||
// natural position by passing `$offset-x` and `$offset-y`.
|
||||
@mixin sprite-position($map, $sprite, $offset-x: 0, $offset-y: 0) {
|
||||
background-position: sprite-position($map, $sprite, $offset-x, $offset-y);
|
||||
}
|
||||
|
||||
// Include the position and (optionally) dimensions of this `$sprite`
|
||||
// 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:
|
||||
//
|
||||
// background: $map no-repeat;
|
||||
@mixin sprite($map, $sprite, $dimensions: false, $offset-x: 0, $offset-y: 0) {
|
||||
@include sprite-position($map, $sprite, $offset-x, $offset-y);
|
||||
@if $dimensions {
|
||||
@include sprite-dimensions($map, $sprite);
|
||||
}
|
||||
}
|
||||
|
||||
// Generates a class for each space separated name in `$sprite-names`.
|
||||
// The class will be of the form .<map-name>-<sprite-name>.
|
||||
//
|
||||
// If a base class is provided, then each class will extend it.
|
||||
//
|
||||
// If `$dimensions` is `true`, the sprite dimensions will specified.
|
||||
@mixin sprites($map, $sprite-names, $base-class: false, $dimensions: false) {
|
||||
@each $sprite-name in $sprite-names {
|
||||
.#{sprite-map-name($map)}-#{$sprite-name} {
|
||||
@if $base-class { @extend #{$base-class}; }
|
||||
@include sprite($map, $sprite-name, $dimensions);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
module Compass
|
||||
end
|
||||
|
||||
%w(dependencies util sass_extensions core_ext version errors).each do |lib|
|
||||
%w(dependencies util sass_extensions core_ext version errors quick_cache).each do |lib|
|
||||
require "compass/#{lib}"
|
||||
end
|
||||
|
||||
@ -13,8 +13,9 @@ module Compass
|
||||
File.expand_path(File.join(File.dirname(__FILE__)))
|
||||
end
|
||||
module_function :base_directory, :lib_directory
|
||||
extend QuickCache
|
||||
end
|
||||
|
||||
%w(configuration frameworks app_integration actions compiler).each do |lib|
|
||||
%w(configuration frameworks app_integration actions compiler sprites).each do |lib|
|
||||
require "compass/#{lib}"
|
||||
end
|
||||
|
@ -61,7 +61,7 @@ This can be done in one of the following ways:
|
||||
compass watch [path/to/project]
|
||||
|
||||
More Resources:
|
||||
* Wiki: http://wiki.github.com/chriseppstein/compass
|
||||
* Website: http://compass-style.org/
|
||||
* Sass: http://sass-lang.com
|
||||
* Community: http://groups.google.com/group/compass-users/
|
||||
|
||||
|
@ -5,7 +5,7 @@ require 'compass/commands/registry'
|
||||
|
||||
%w(base generate_grid_background help list_frameworks project_base
|
||||
update_project watch_project create_project imports installer_command
|
||||
print_version project_stats stamp_pattern validate_project
|
||||
print_version project_stats stamp_pattern sprite validate_project
|
||||
write_configuration interactive unpack_extension).each do |lib|
|
||||
require "compass/commands/#{lib}"
|
||||
end
|
||||
|
87
lib/compass/commands/sprite.rb
Normal file
87
lib/compass/commands/sprite.rb
Normal file
@ -0,0 +1,87 @@
|
||||
require 'compass/commands/project_base'
|
||||
require 'compass/commands/update_project'
|
||||
|
||||
module Compass
|
||||
module Commands
|
||||
module SpriteOptionsParser
|
||||
def set_options(opts)
|
||||
opts.on("-f SPRITE_FILE") do |output_file|
|
||||
self.options[:output_file] = output_file
|
||||
end
|
||||
opts.banner = %Q{
|
||||
Usage: compass sprite [options] "images/path/to/sprites/*.png"
|
||||
|
||||
Description:
|
||||
Generate a sprite import based on the given sprite directory.
|
||||
Alternatively, you can simply do this in your sass files:
|
||||
|
||||
@import "sprite-folder/*.png"
|
||||
|
||||
And a magical, custom made sprite file will be imported.
|
||||
|
||||
Options:
|
||||
}.strip.split("\n").map{|l| l.gsub(/^ {0,10}/,'')}.join("\n")
|
||||
|
||||
super
|
||||
end
|
||||
end
|
||||
class Sprite < ProjectBase
|
||||
|
||||
register :sprite
|
||||
|
||||
def initialize(working_path, options)
|
||||
super
|
||||
assert_project_directory_exists!
|
||||
end
|
||||
|
||||
def perform
|
||||
sprites = Compass::Sprites.new
|
||||
relative_uri = options[:uri].gsub(/^#{Compass.configuration.images_dir}\//, '')
|
||||
sprite_images = Compass::Sprites.discover_sprites(relative_uri)
|
||||
image_names = sprite_images.map{|i| File.basename(i, '.png')}
|
||||
sprites.path, sprites.name = Compass::Sprites.path_and_name(relative_uri)
|
||||
options[:output_file] ||= File.join(Compass.configuration.sass_path, "sprites", "_#{sprites.name}.#{Compass.configuration.preferred_syntax}")
|
||||
contents = sprites.content_for_images(relative_uri, sprites.name, image_names)
|
||||
if options[:output_file][-4..-1] != "scss"
|
||||
contents = Sass::Engine.new(contents, Compass.sass_engine_options.merge(:syntax => :scss)).to_tree.to_sass
|
||||
end
|
||||
directory File.dirname(options[:output_file])
|
||||
write_file options[:output_file], contents
|
||||
end
|
||||
|
||||
class << self
|
||||
|
||||
def option_parser(arguments)
|
||||
parser = Compass::Exec::CommandOptionParser.new(arguments)
|
||||
parser.extend(Compass::Exec::GlobalOptionsParser)
|
||||
parser.extend(Compass::Exec::ProjectOptionsParser)
|
||||
parser.extend(SpriteOptionsParser)
|
||||
end
|
||||
|
||||
def usage
|
||||
option_parser([]).to_s
|
||||
end
|
||||
|
||||
def description(command)
|
||||
"Generate an import for your sprites."
|
||||
end
|
||||
|
||||
def parse!(arguments)
|
||||
parser = option_parser(arguments)
|
||||
parser.parse!
|
||||
parse_arguments!(parser, arguments)
|
||||
parser.options
|
||||
end
|
||||
|
||||
def parse_arguments!(parser, arguments)
|
||||
parser.options[:uri] = arguments.shift
|
||||
unless arguments.size == 0
|
||||
raise Compass::Error, "Please specify at least one image to sprite."
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -22,6 +22,8 @@ module Compass
|
||||
plugin_opts[:cache] = cache unless cache.nil?
|
||||
plugin_opts[:cache_location] = cache_path unless cache_path.nil?
|
||||
plugin_opts.merge!(sass_options || {})
|
||||
plugin_opts[:load_paths] ||= []
|
||||
plugin_opts[:load_paths] << Compass::Sprites.new
|
||||
plugin_opts
|
||||
end
|
||||
|
||||
@ -57,6 +59,7 @@ module Compass
|
||||
load_paths << framework.stylesheets_directory if File.exists?(framework.stylesheets_directory)
|
||||
end
|
||||
load_paths += resolve_additional_import_paths
|
||||
load_paths << Compass::Sprites.new
|
||||
load_paths
|
||||
end
|
||||
end
|
||||
|
@ -2,5 +2,11 @@ begin
|
||||
require 'sass'
|
||||
rescue LoadError
|
||||
require 'rubygems'
|
||||
require 'sass'
|
||||
begin
|
||||
require 'sass'
|
||||
rescue LoadError
|
||||
puts "Unable to load Sass. Please install it with one of the following commands:"
|
||||
puts " gem install sass --pre"
|
||||
raise
|
||||
end
|
||||
end
|
||||
|
@ -47,7 +47,7 @@ This can be done in one of the following ways:
|
||||
compass watch [path/to/project]
|
||||
|
||||
More Resources:
|
||||
* Wiki: http://wiki.github.com/chriseppstein/compass
|
||||
* Website: http://compass-style.org/
|
||||
* Sass: http://sass-lang.com
|
||||
* Community: http://groups.google.com/group/compass-users/
|
||||
NEXTSTEPS
|
||||
|
15
lib/compass/quick_cache.rb
Normal file
15
lib/compass/quick_cache.rb
Normal file
@ -0,0 +1,15 @@
|
||||
module QuickCache
|
||||
|
||||
# cache a value in memory for just a few seconds
|
||||
# This can speed up reads of values that change relatively infrequently
|
||||
# but might be read many times in a short burst of reads.
|
||||
def quick_cache(key, ttl = 1)
|
||||
@quick_cache ||= {}
|
||||
if @quick_cache[key] && @quick_cache[key].first > Time.now - ttl
|
||||
@quick_cache[key].last
|
||||
else
|
||||
(@quick_cache[key] = [Time.now, yield]).last
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -4,7 +4,7 @@ end
|
||||
%w(
|
||||
selectors enumerate urls display
|
||||
inline_image image_size constants gradient_support
|
||||
font_files lists colors trig
|
||||
font_files lists colors trig sprites
|
||||
).each do |func|
|
||||
require "compass/sass_extensions/functions/#{func}"
|
||||
end
|
||||
@ -22,6 +22,7 @@ module Sass::Script::Functions
|
||||
include Compass::SassExtensions::Functions::Lists
|
||||
include Compass::SassExtensions::Functions::Colors
|
||||
include Compass::SassExtensions::Functions::Trig
|
||||
include Compass::SassExtensions::Functions::Sprites
|
||||
end
|
||||
|
||||
# Wierd that this has to be re-included to pick up sub-modules. Ruby bug?
|
||||
|
@ -13,17 +13,6 @@ module Compass::SassExtensions::Functions::ImageSize
|
||||
Sass::Script::Number.new(height, ["px"])
|
||||
end
|
||||
|
||||
private
|
||||
def real_path(image_file)
|
||||
path = image_file.value
|
||||
# Compute the real path to the image on the file stystem if the images_dir is set.
|
||||
if Compass.configuration.images_path
|
||||
File.join(Compass.configuration.images_path, path)
|
||||
else
|
||||
File.join(Compass.configuration.project_path, path)
|
||||
end
|
||||
end
|
||||
|
||||
class ImageProperties
|
||||
def initialize(file)
|
||||
@file = file
|
||||
@ -55,6 +44,17 @@ private
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def real_path(image_file)
|
||||
path = image_file.value
|
||||
# Compute the real path to the image on the file stystem if the images_dir is set.
|
||||
if Compass.configuration.images_path
|
||||
File.join(Compass.configuration.images_path, path)
|
||||
else
|
||||
File.join(Compass.configuration.project_path, path)
|
||||
end
|
||||
end
|
||||
|
||||
class JPEG
|
||||
attr_reader :width, :height, :bits
|
||||
|
||||
|
324
lib/compass/sass_extensions/functions/sprites.rb
Normal file
324
lib/compass/sass_extensions/functions/sprites.rb
Normal file
@ -0,0 +1,324 @@
|
||||
require 'chunky_png'
|
||||
|
||||
module Compass::SassExtensions::Functions::Sprites
|
||||
ZERO = Sass::Script::Number::new(0)
|
||||
|
||||
# Provides a consistent interface for getting a variable in ruby
|
||||
# from a keyword argument hash that accounts for underscores/dash equivalence
|
||||
# and allows the caller to pass a symbol instead of a string.
|
||||
module VariableReader
|
||||
def get_var(variable_name)
|
||||
self[variable_name.to_s.gsub(/-/,"_")]
|
||||
end
|
||||
end
|
||||
|
||||
class SpriteMap < Sass::Script::Literal
|
||||
|
||||
attr_accessor :image_names, :path, :name, :options
|
||||
attr_accessor :images, :width, :height
|
||||
|
||||
def self.from_uri(uri, context, kwargs)
|
||||
path, name = Compass::Sprites.path_and_name(uri.value)
|
||||
new(Compass::Sprites.discover_sprites(uri.value), path, name, context, kwargs)
|
||||
end
|
||||
|
||||
def initialize(image_names, path, name, context, options)
|
||||
@image_names, @path, @name, @options = image_names, path, name, options
|
||||
@images = nil
|
||||
@width = nil
|
||||
@height = nil
|
||||
@evaluation_context = context
|
||||
validate!
|
||||
compute_image_metadata!
|
||||
end
|
||||
|
||||
def sprite_names
|
||||
image_names.map{|f| Compass::Sprites.sprite_name(f) }
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
# Calculates the overal image dimensions
|
||||
# collects image sizes and input parameters for each sprite
|
||||
def compute_image_metadata!
|
||||
@images = []
|
||||
@width = 0
|
||||
image_names.each do |file|
|
||||
relative_file = file.gsub(Compass.configuration.images_path+"/", "")
|
||||
width, height = Compass::SassExtensions::Functions::ImageSize::ImageProperties.new(file).size
|
||||
sprite_name = Compass::Sprites.sprite_name(relative_file)
|
||||
@width = [@width, width].max
|
||||
@images << {
|
||||
:name => sprite_name,
|
||||
:file => file,
|
||||
:relative_file => relative_file,
|
||||
:height => height,
|
||||
:width => width,
|
||||
:repeat => repeat_for(sprite_name),
|
||||
:spacing => spacing_for(sprite_name),
|
||||
:position => position_for(sprite_name)
|
||||
}
|
||||
end
|
||||
@images.each_with_index do |image, index|
|
||||
if index == 0
|
||||
image[:top] = 0
|
||||
else
|
||||
last_image = @images[index-1]
|
||||
image[:top] = last_image[:top] + last_image[:height] + [image[:spacing], last_image[:spacing]].max
|
||||
end
|
||||
if image[:position].unit_str == "%"
|
||||
image[:left] = (@width - image[:width]) * (image[:position].value / 100)
|
||||
else
|
||||
image[:left] = image[:position].value
|
||||
end
|
||||
end
|
||||
@height = @images.last[:top] + @images.last[:height]
|
||||
end
|
||||
|
||||
def position_for(name)
|
||||
options.get_var("#{name}-position") || options.get_var("position") || Sass::Script::Number.new(0, ["px"])
|
||||
end
|
||||
|
||||
def repeat_for(name)
|
||||
if (var = options.get_var("#{name}-repeat"))
|
||||
var.value
|
||||
elsif (var = options.get_var("repeat"))
|
||||
var.value
|
||||
else
|
||||
"no-repeat"
|
||||
end
|
||||
end
|
||||
|
||||
def spacing_for(name)
|
||||
(options.get_var("#{name}-spacing") ||
|
||||
options.get_var("spacing") ||
|
||||
ZERO).value
|
||||
end
|
||||
|
||||
def image_for(name)
|
||||
@images.detect{|img| img[:name] == name}
|
||||
end
|
||||
|
||||
# Calculate the size of the sprite
|
||||
def size
|
||||
[width, height]
|
||||
end
|
||||
|
||||
# Generate a sprite image if necessary
|
||||
def generate
|
||||
if generation_required?
|
||||
save!(construct_sprite)
|
||||
end
|
||||
end
|
||||
|
||||
def generation_required?
|
||||
!File.exists?(filename) || outdated?
|
||||
end
|
||||
|
||||
# Returns a PNG object
|
||||
def construct_sprite
|
||||
output_png = ChunkyPNG::Image.new(width, height, ChunkyPNG::Color::TRANSPARENT)
|
||||
images.each do |image|
|
||||
input_png = ChunkyPNG::Image.from_file(image[:file])
|
||||
if image[:repeat] == "no-repeat"
|
||||
output_png.replace input_png, image[:left], image[:top]
|
||||
else
|
||||
x = image[:left] - (image[:left] / image[:width]).ceil * image[:width]
|
||||
while x < width do
|
||||
output_png.replace input_png, x, image[:top]
|
||||
x += image[:width]
|
||||
end
|
||||
end
|
||||
end
|
||||
output_png
|
||||
end
|
||||
|
||||
# The on-the-disk filename of the sprite
|
||||
def filename
|
||||
File.join(Compass.configuration.images_path, "#{path}.png")
|
||||
end
|
||||
|
||||
# saves the sprite for later retrieval
|
||||
def save!(output_png)
|
||||
output_png.save filename
|
||||
end
|
||||
|
||||
# All the full-path filenames involved in this sprite
|
||||
def image_filenames
|
||||
image_names.map do |image_name|
|
||||
File.join(Compass.configuration.images_path, image_name)
|
||||
end
|
||||
end
|
||||
|
||||
# Checks whether this sprite is outdated
|
||||
def outdated?
|
||||
last_update = self.mtime
|
||||
image_filenames.each do |image|
|
||||
return true if File.mtime(image) > last_update
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
def mtime
|
||||
File.mtime(filename)
|
||||
end
|
||||
|
||||
def inspect
|
||||
to_s
|
||||
end
|
||||
|
||||
def to_s(options = self.options)
|
||||
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
|
||||
|
||||
end
|
||||
|
||||
# Creates a SpriteMap object. A sprite map, when used in a property is the same
|
||||
# as calling sprite-url. So the following background properties are equivalent:
|
||||
#
|
||||
# $icons: sprite-map("icons/*.png");
|
||||
# background: sprite-url($icons) no-repeat;
|
||||
# background: $icons no-repeat;
|
||||
#
|
||||
# The sprite map object will generate the sprite map image, if necessary,
|
||||
# the first time it is converted to a url. Simply constructing it has no side-effects.
|
||||
def sprite_map(glob, kwargs = {})
|
||||
kwargs.extend VariableReader
|
||||
SpriteMap.from_uri(glob, self, kwargs)
|
||||
end
|
||||
Sass::Script::Functions.declare :sprite_map, [:glob], :var_kwargs => true
|
||||
|
||||
# Returns the image and background position for use in a single shorthand property:
|
||||
#
|
||||
# $icons: sprite-map("icons/*.png"); // contains icons/new.png among others.
|
||||
# background: sprite($icons, new) no-repeat;
|
||||
#
|
||||
# Becomes:
|
||||
#
|
||||
# background: url('/images/icons.png?12345678') 0 -24px no-repeat;
|
||||
def sprite(map, sprite, offset_x = ZERO, offset_y = ZERO)
|
||||
unless map.is_a?(SpriteMap)
|
||||
missing_sprite!("sprite")
|
||||
end
|
||||
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.)
|
||||
end
|
||||
url = sprite_url(map)
|
||||
position = sprite_position(map, sprite, offset_x, offset_y)
|
||||
Sass::Script::List.new([url] + position.value, :space)
|
||||
end
|
||||
Sass::Script::Functions.declare :sprite, [:map, :sprite]
|
||||
Sass::Script::Functions.declare :sprite, [:map, :sprite, :offset_x]
|
||||
Sass::Script::Functions.declare :sprite, [:map, :sprite, :offset_x, :offset_y]
|
||||
|
||||
# Returns the name of a sprite map
|
||||
# The name is derived from the folder than contains the sprites.
|
||||
def sprite_map_name(map)
|
||||
unless map.is_a?(SpriteMap)
|
||||
missing_sprite!("sprite-map-name")
|
||||
end
|
||||
Sass::Script::String.new(map.name)
|
||||
end
|
||||
Sass::Script::Functions.declare :sprite_name, [:sprite]
|
||||
|
||||
# Returns the path to the original image file for the sprite with the given name
|
||||
def sprite_file(map, sprite)
|
||||
unless map.is_a?(SpriteMap)
|
||||
missing_sprite!("sprite-file")
|
||||
end
|
||||
if image = map.image_for(sprite.value)
|
||||
Sass::Script::String.new(image[:relative_file])
|
||||
else
|
||||
missing_image!(map, sprite)
|
||||
end
|
||||
end
|
||||
Sass::Script::Functions.declare :sprite_file, [:map, :sprite]
|
||||
|
||||
# Returns a url to the sprite image.
|
||||
def sprite_url(map)
|
||||
unless map.is_a?(SpriteMap)
|
||||
missing_sprite!("sprite-url")
|
||||
end
|
||||
map.generate
|
||||
image_url(Sass::Script::String.new("#{map.path}.png"))
|
||||
end
|
||||
Sass::Script::Functions.declare :sprite_url, [:map]
|
||||
|
||||
# Returns the position for the original image in the sprite.
|
||||
# This is suitable for use as a value to background-position:
|
||||
#
|
||||
# $icons: sprite-map("icons/*.png");
|
||||
# background-position: sprite-position($icons, new);
|
||||
#
|
||||
# Might generate something like:
|
||||
#
|
||||
# background-position: 0 -34px;
|
||||
#
|
||||
# You can adjust the background relative to this position by passing values for
|
||||
# `$offset-x` and `$offset-y`:
|
||||
#
|
||||
# $icons: sprite-map("icons/*.png");
|
||||
# background-position: sprite-position($icons, new, 3px, -2px);
|
||||
#
|
||||
# Would change the above output to:
|
||||
#
|
||||
# background-position: 3px -36px;
|
||||
def sprite_position(map, sprite = nil, offset_x = ZERO, offset_y = ZERO)
|
||||
unless map.is_a?(SpriteMap)
|
||||
missing_sprite!("sprite-position")
|
||||
end
|
||||
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.)
|
||||
end
|
||||
image = map.image_for(sprite.value)
|
||||
unless image
|
||||
missing_image!(map, sprite)
|
||||
end
|
||||
if offset_x.unit_str == "%"
|
||||
x = offset_x # CE: Shouldn't this be a percentage of the total width?
|
||||
else
|
||||
x = offset_x.value - image[:left]
|
||||
x = Sass::Script::Number.new(x, x == 0 ? [] : ["px"])
|
||||
end
|
||||
y = offset_y.value - image[:top]
|
||||
y = Sass::Script::Number.new(y, y == 0 ? [] : ["px"])
|
||||
Sass::Script::List.new([x, y],:space)
|
||||
end
|
||||
Sass::Script::Functions.declare :sprite_position, [:map]
|
||||
Sass::Script::Functions.declare :sprite_position, [:map, :sprite]
|
||||
Sass::Script::Functions.declare :sprite_position, [:map, :sprite, :offset_x]
|
||||
Sass::Script::Functions.declare :sprite_position, [:map, :sprite, :offset_x, :offset_y]
|
||||
|
||||
def sprite_image(*args)
|
||||
raise Sass::SyntaxError, %Q(The sprite-image() function has been replaced by sprite(). See http://beta.compass-style.org/help/tutorials/spriting/ for more information.)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def missing_image!(map, sprite)
|
||||
raise Sass::SyntaxError, "No sprite called #{sprite} found in sprite map #{map.path}/#{map.name}. Did you mean one of: #{map.sprite_names.join(", ")}"
|
||||
end
|
||||
|
||||
def missing_sprite!(function_name)
|
||||
raise Sass::SyntaxError, %Q(The first argument to #{function_name}() must be a sprite map. See http://beta.compass-style.org/help/tutorials/spriting/ for more information.)
|
||||
end
|
||||
|
||||
end
|
@ -6,7 +6,7 @@ module Sass
|
||||
visitor.visit(self)
|
||||
visitor.down(self) if children.any? and visitor.respond_to?(:down)
|
||||
if is_a?(ImportNode) && visitor.import?(self)
|
||||
root = Sass::Files.tree_for(import, @options)
|
||||
root = Sass::Engine.for_file(import, @options).to_tree
|
||||
imported_children = root.children
|
||||
end
|
||||
|
||||
|
122
lib/compass/sprites.rb
Normal file
122
lib/compass/sprites.rb
Normal file
@ -0,0 +1,122 @@
|
||||
module Compass
|
||||
class Sprites < Sass::Importers::Base
|
||||
attr_accessor :name
|
||||
attr_accessor :path
|
||||
|
||||
class << self
|
||||
def path_and_name(uri)
|
||||
if uri =~ %r{((.+/)?(.+))/(.+?)\.png}
|
||||
[$1, $3, $4]
|
||||
end
|
||||
end
|
||||
|
||||
def discover_sprites(uri)
|
||||
glob = File.join(Compass.configuration.images_path, uri)
|
||||
Dir.glob(glob).sort
|
||||
end
|
||||
|
||||
def sprite_name(file)
|
||||
File.basename(file, '.png')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def find_relative(*args)
|
||||
nil
|
||||
end
|
||||
|
||||
def find(uri, options)
|
||||
if uri =~ /\.png$/
|
||||
self.path, self.name = Compass::Sprites.path_and_name(uri)
|
||||
options.merge! :filename => name, :syntax => :scss, :importer => self
|
||||
sprite_files = Compass::Sprites.discover_sprites(uri)
|
||||
image_names = sprite_files.map {|i| Compass::Sprites.sprite_name(i) }
|
||||
Sass::Engine.new(content_for_images(uri, name, image_names), options)
|
||||
end
|
||||
end
|
||||
|
||||
def content_for_images(uri, name, images)
|
||||
<<-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;
|
||||
|
||||
// These variables control the generated sprite output
|
||||
// You can override them selectively before you import this file.
|
||||
#{images.map do |sprite_name|
|
||||
<<-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}
|
||||
|
||||
$#{name}-sprites: sprite-map("#{uri}",
|
||||
#{images.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")});
|
||||
|
||||
// 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-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) {
|
||||
@include sprites($#{name}-sprites, $sprite-names, $#{name}-sprite-base-class, $dimensions)
|
||||
}
|
||||
|
||||
// Generates a class for each sprited image.
|
||||
@mixin all-#{name}-sprites($dimensions: $#{name}-sprite-dimensions) {
|
||||
@include #{name}-sprites(#{images.join(" ")}, $dimensions);
|
||||
}
|
||||
SCSS
|
||||
end
|
||||
|
||||
def key(uri, options)
|
||||
[self.class.name + ":" + File.dirname(File.expand_path(uri)),
|
||||
File.basename(uri)]
|
||||
end
|
||||
|
||||
def mtime(uri, options)
|
||||
Compass.quick_cache("mtime:#{uri}") do
|
||||
self.path, self.name = Compass::Sprites.path_and_name(uri)
|
||||
glob = File.join(Compass.configuration.images_path, uri)
|
||||
Dir.glob(glob).inject(Time.at(0)) do |max_time, file|
|
||||
(t = File.mtime(file)) > max_time ? t : max_time
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
""
|
||||
end
|
||||
|
||||
end
|
||||
end
|
7
spec/spec_helper.rb
Normal file
7
spec/spec_helper.rb
Normal file
@ -0,0 +1,7 @@
|
||||
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
||||
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
||||
|
||||
require 'rubygems'
|
||||
require 'compass'
|
||||
require 'rspec'
|
||||
require 'rspec/autorun'
|
390
spec/sprites_spec.rb
Normal file
390
spec/sprites_spec.rb
Normal file
@ -0,0 +1,390 @@
|
||||
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
||||
require "compass/sprites"
|
||||
require 'digest/md5'
|
||||
|
||||
describe Compass::Sprites do
|
||||
|
||||
before :each do
|
||||
@images_src_path = File.join(File.dirname(__FILE__), 'test_project', 'public', 'images')
|
||||
@images_tmp_path = File.join(File.dirname(__FILE__), 'test_project', 'public', 'images-tmp')
|
||||
FileUtils.cp_r @images_src_path, @images_tmp_path
|
||||
Compass.configuration.images_path = @images_tmp_path
|
||||
Compass.configure_sass_plugin!
|
||||
end
|
||||
|
||||
after :each do
|
||||
FileUtils.rm_r @images_tmp_path
|
||||
end
|
||||
|
||||
def image_size(file)
|
||||
IO.read(File.join(@images_tmp_path, file))[0x10..0x18].unpack('NN')
|
||||
end
|
||||
|
||||
def image_md5(file)
|
||||
md5 = Digest::MD5.new
|
||||
md5.update IO.read(File.join(@images_tmp_path, file))
|
||||
md5.hexdigest
|
||||
end
|
||||
|
||||
def render(scss)
|
||||
scss = %Q(@import "compass"; #{scss})
|
||||
options = Compass.sass_engine_options
|
||||
options[:line_comments] = false
|
||||
options[:style] = :expanded
|
||||
options[:syntax] = :scss
|
||||
css = Sass::Engine.new(scss, options).render
|
||||
# reformat to fit result of heredoc:
|
||||
" #{css.gsub('@charset "UTF-8";', '').gsub(/\n/, "\n ").strip}\n"
|
||||
end
|
||||
|
||||
# DEFAULT USAGE:
|
||||
|
||||
it "should generate sprite classes" do
|
||||
css = render <<-SCSS
|
||||
@import "squares/*.png";
|
||||
@include all-squares-sprites;
|
||||
SCSS
|
||||
css.should == <<-CSS
|
||||
.squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty {
|
||||
background: url('/squares.png') no-repeat;
|
||||
}
|
||||
|
||||
.squares-ten-by-ten {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.squares-twenty-by-twenty {
|
||||
background-position: 0 -10px;
|
||||
}
|
||||
CSS
|
||||
image_size('squares.png').should == [20, 30]
|
||||
image_md5('squares.png').should == 'e8cd71d546aae6951ea44cb01af35820'
|
||||
end
|
||||
|
||||
it "should generate sprite classes with dimensions" do
|
||||
css = render <<-SCSS
|
||||
$squares-sprite-dimensions: true;
|
||||
@import "squares/*.png";
|
||||
@include all-squares-sprites;
|
||||
SCSS
|
||||
css.should == <<-CSS
|
||||
.squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty {
|
||||
background: url('/squares.png') no-repeat;
|
||||
}
|
||||
|
||||
.squares-ten-by-ten {
|
||||
background-position: 0 0;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
.squares-twenty-by-twenty {
|
||||
background-position: 0 -10px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
CSS
|
||||
image_size('squares.png').should == [20, 30]
|
||||
end
|
||||
|
||||
it "should provide sprite mixin" do
|
||||
css = render <<-SCSS
|
||||
@import "squares/*.png";
|
||||
|
||||
.cubicle {
|
||||
@include squares-sprite("ten-by-ten");
|
||||
}
|
||||
|
||||
.large-cube {
|
||||
@include squares-sprite("twenty-by-twenty", true);
|
||||
}
|
||||
SCSS
|
||||
css.should == <<-CSS
|
||||
.squares-sprite, .cubicle, .large-cube {
|
||||
background: url('/squares.png') no-repeat;
|
||||
}
|
||||
|
||||
.cubicle {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.large-cube {
|
||||
background-position: 0 -10px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
CSS
|
||||
image_size('squares.png').should == [20, 30]
|
||||
end
|
||||
|
||||
# CUSTOMIZATIONS:
|
||||
|
||||
it "should be possible to change the base class" do
|
||||
css = render <<-SCSS
|
||||
$squares-sprite-base-class: ".circles";
|
||||
@import "squares/*.png";
|
||||
SCSS
|
||||
css.should == <<-CSS
|
||||
.circles {
|
||||
background: url('/squares.png') no-repeat;
|
||||
}
|
||||
CSS
|
||||
image_size('squares.png').should == [20, 30]
|
||||
end
|
||||
|
||||
it "should calculate the spacing between images but not before first image" do
|
||||
css = render <<-SCSS
|
||||
$squares-ten-by-ten-spacing: 33px;
|
||||
@import "squares/*.png";
|
||||
@include all-squares-sprites;
|
||||
SCSS
|
||||
css.should == <<-CSS
|
||||
.squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty {
|
||||
background: url('/squares.png') no-repeat;
|
||||
}
|
||||
|
||||
.squares-ten-by-ten {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.squares-twenty-by-twenty {
|
||||
background-position: 0 -43px;
|
||||
}
|
||||
CSS
|
||||
image_size('squares.png').should == [20, 63]
|
||||
end
|
||||
|
||||
it "should calculate the spacing between images" do
|
||||
css = render <<-SCSS
|
||||
$squares-twenty-by-twenty-spacing: 33px;
|
||||
@import "squares/*.png";
|
||||
@include all-squares-sprites;
|
||||
SCSS
|
||||
css.should == <<-CSS
|
||||
.squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty {
|
||||
background: url('/squares.png') no-repeat;
|
||||
}
|
||||
|
||||
.squares-ten-by-ten {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.squares-twenty-by-twenty {
|
||||
background-position: 0 -43px;
|
||||
}
|
||||
CSS
|
||||
image_size('squares.png').should == [20, 63]
|
||||
end
|
||||
|
||||
it "should calculate the maximum spacing between images" do
|
||||
css = render <<-SCSS
|
||||
$squares-ten-by-ten-spacing: 44px;
|
||||
$squares-twenty-by-twenty-spacing: 33px;
|
||||
@import "squares/*.png";
|
||||
@include all-squares-sprites;
|
||||
SCSS
|
||||
css.should == <<-CSS
|
||||
.squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty {
|
||||
background: url('/squares.png') no-repeat;
|
||||
}
|
||||
|
||||
.squares-ten-by-ten {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.squares-twenty-by-twenty {
|
||||
background-position: 0 -54px;
|
||||
}
|
||||
CSS
|
||||
image_size('squares.png').should == [20, 74]
|
||||
end
|
||||
|
||||
it "should calculate the maximum spacing between images in reversed order" do
|
||||
css = render <<-SCSS
|
||||
$squares-ten-by-ten-spacing: 33px;
|
||||
$squares-twenty-by-twenty-spacing: 44px;
|
||||
@import "squares/*.png";
|
||||
@include all-squares-sprites;
|
||||
SCSS
|
||||
css.should == <<-CSS
|
||||
.squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty {
|
||||
background: url('/squares.png') no-repeat;
|
||||
}
|
||||
|
||||
.squares-ten-by-ten {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.squares-twenty-by-twenty {
|
||||
background-position: 0 -54px;
|
||||
}
|
||||
CSS
|
||||
image_size('squares.png').should == [20, 74]
|
||||
end
|
||||
|
||||
it "should calculate the default spacing between images" do
|
||||
css = render <<-SCSS
|
||||
$squares-spacing: 22px;
|
||||
@import "squares/*.png";
|
||||
@include all-squares-sprites;
|
||||
SCSS
|
||||
css.should == <<-CSS
|
||||
.squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty {
|
||||
background: url('/squares.png') no-repeat;
|
||||
}
|
||||
|
||||
.squares-ten-by-ten {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.squares-twenty-by-twenty {
|
||||
background-position: 0 -32px;
|
||||
}
|
||||
CSS
|
||||
image_size('squares.png').should == [20, 52]
|
||||
end
|
||||
|
||||
it "should use position adjustments in functions" do
|
||||
css = render <<-SCSS
|
||||
$squares: sprite-map("squares/*.png", $position: 100%);
|
||||
.squares-sprite {
|
||||
background: $squares no-repeat;
|
||||
}
|
||||
|
||||
.adjusted-percentage {
|
||||
background-position: sprite-position($squares, ten-by-ten, 100%);
|
||||
}
|
||||
|
||||
.adjusted-px-1 {
|
||||
background-position: sprite-position($squares, ten-by-ten, 4px);
|
||||
}
|
||||
|
||||
.adjusted-px-2 {
|
||||
background-position: sprite-position($squares, twenty-by-twenty, -3px, 2px);
|
||||
}
|
||||
SCSS
|
||||
css.should == <<-CSS
|
||||
.squares-sprite {
|
||||
background: url('/squares.png') no-repeat;
|
||||
}
|
||||
|
||||
.adjusted-percentage {
|
||||
background-position: 100% 0;
|
||||
}
|
||||
|
||||
.adjusted-px-1 {
|
||||
background-position: -6px 0;
|
||||
}
|
||||
|
||||
.adjusted-px-2 {
|
||||
background-position: -3px -8px;
|
||||
}
|
||||
CSS
|
||||
image_size('squares.png').should == [20, 30]
|
||||
image_md5('squares.png').should == 'b61700e6d402d9df5f3820b73479f371'
|
||||
end
|
||||
|
||||
it "should use position adjustments in mixins" do
|
||||
css = render <<-SCSS
|
||||
$squares-position: 100%;
|
||||
@import "squares/*.png";
|
||||
|
||||
.adjusted-percentage {
|
||||
@include squares-sprite("ten-by-ten", $offset-x: 100%);
|
||||
}
|
||||
|
||||
.adjusted-px-1 {
|
||||
@include squares-sprite("ten-by-ten", $offset-x: 4px);
|
||||
}
|
||||
|
||||
.adjusted-px-2 {
|
||||
@include squares-sprite("twenty-by-twenty", $offset-x: -3px, $offset-y: 2px);
|
||||
}
|
||||
SCSS
|
||||
css.should == <<-CSS
|
||||
.squares-sprite, .adjusted-percentage, .adjusted-px-1, .adjusted-px-2 {
|
||||
background: url('/squares.png') no-repeat;
|
||||
}
|
||||
|
||||
.adjusted-percentage {
|
||||
background-position: 100% 0;
|
||||
}
|
||||
|
||||
.adjusted-px-1 {
|
||||
background-position: -6px 0;
|
||||
}
|
||||
|
||||
.adjusted-px-2 {
|
||||
background-position: -3px -8px;
|
||||
}
|
||||
CSS
|
||||
image_size('squares.png').should == [20, 30]
|
||||
image_md5('squares.png').should == 'b61700e6d402d9df5f3820b73479f371'
|
||||
end
|
||||
|
||||
it "should repeat the image" do
|
||||
css = render <<-SCSS
|
||||
$squares-repeat: repeat;
|
||||
@import "squares/*.png";
|
||||
@include all-squares-sprites;
|
||||
SCSS
|
||||
css.should == <<-CSS
|
||||
.squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty {
|
||||
background: url('/squares.png') no-repeat;
|
||||
}
|
||||
|
||||
.squares-ten-by-ten {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.squares-twenty-by-twenty {
|
||||
background-position: 0 -10px;
|
||||
}
|
||||
CSS
|
||||
image_size('squares.png').should == [20, 30]
|
||||
image_md5('squares.png').should == '0187306f3858136feee87d3017e7f307'
|
||||
end
|
||||
|
||||
it "should provide a nice errors for lemonade's old users" do
|
||||
proc do
|
||||
render <<-SCSS
|
||||
.squares {
|
||||
background: sprite-url("squares/*.png") no-repeat;
|
||||
}
|
||||
SCSS
|
||||
end.should raise_error Sass::SyntaxError,
|
||||
%q(The first argument to sprite-url() must be a sprite map. See http://beta.compass-style.org/help/tutorials/spriting/ for more information.)
|
||||
proc do
|
||||
render <<-SCSS
|
||||
.squares {
|
||||
background: sprite-image("squares/twenty-by-twenty.png") no-repeat;
|
||||
}
|
||||
SCSS
|
||||
end.should raise_error Sass::SyntaxError,
|
||||
%q(The sprite-image() function has been replaced by sprite(). See http://beta.compass-style.org/help/tutorials/spriting/ for more information.)
|
||||
proc do
|
||||
render <<-SCSS
|
||||
@import "squares/*.png";
|
||||
|
||||
.squares {
|
||||
background: sprite-position("squares/twenty-by-twenty.png") no-repeat;
|
||||
}
|
||||
SCSS
|
||||
end.should raise_error Sass::SyntaxError,
|
||||
%q(The first argument to sprite-position() must be a sprite map. See http://beta.compass-style.org/help/tutorials/spriting/ for more information.)
|
||||
end
|
||||
|
||||
it "should work even if @import is missing" do
|
||||
actual_css = render <<-SCSS
|
||||
.squares {
|
||||
background: sprite(sprite-map("squares/*.png"), twenty-by-twenty) no-repeat;
|
||||
}
|
||||
SCSS
|
||||
actual_css.should == <<-CSS
|
||||
.squares {
|
||||
background: url('/squares.png') 0 -10px no-repeat;
|
||||
}
|
||||
CSS
|
||||
end
|
||||
|
||||
end
|
BIN
spec/test_project/public/images/squares/ten-by-ten.png
Normal file
BIN
spec/test_project/public/images/squares/ten-by-ten.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
BIN
spec/test_project/public/images/squares/twenty-by-twenty.png
Normal file
BIN
spec/test_project/public/images/squares/twenty-by-twenty.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
Loading…
Reference in New Issue
Block a user