├── test ├── images │ ├── ok.png │ ├── date.png │ ├── gift.png │ ├── help.png │ ├── lock.png │ ├── love.png │ ├── mail.png │ ├── pin.png │ ├── tool.png │ ├── zoom.png │ ├── camera.png │ ├── cloud1.png │ ├── cloud2.png │ ├── cloud3.png │ ├── cloud4.png │ ├── config.png │ ├── file1.png │ ├── file2.png │ ├── file3.png │ ├── file4.png │ ├── gamepad.png │ ├── garbage.png │ ├── letters.png │ ├── monitor.png │ ├── notepad.png │ ├── phone.png │ ├── picture.png │ ├── sound.png │ ├── unlock.png │ ├── wallet.png │ ├── openmail.png │ └── suitcase.png ├── unit │ └── stitches.js ├── .jshintrc └── index.html ├── .gitignore ├── src ├── img │ ├── stripes80.gif │ ├── stripes90.gif │ ├── test │ │ ├── github.png │ │ ├── gmail.png │ │ ├── tumblr.png │ │ ├── linkedin.png │ │ ├── twitter.png │ │ └── stackoverflow.png │ └── checkerboard10.png ├── templates │ ├── sprite.tpl │ ├── less-markup.tpl │ ├── css-markup.tpl │ ├── css.tpl │ ├── less.tpl │ ├── downloads.tpl │ └── stitches.tpl ├── css │ ├── stitches.css │ ├── toolbar.css │ ├── sprite.css │ ├── base.css │ └── palette.css ├── js │ ├── wrap │ │ ├── jquery.js │ │ └── modernizr.js │ ├── util │ │ ├── array.js │ │ ├── templates.js │ │ └── util.js │ ├── stitches.js │ ├── stylesheet │ │ ├── css.js │ │ ├── less.js │ │ └── base.js │ ├── manager │ │ ├── stylesheet.js │ │ ├── file.js │ │ └── layout.js │ ├── layout │ │ ├── base.js │ │ ├── vertical.js │ │ ├── horizontal.js │ │ └── compact.js │ └── module │ │ ├── drop-box.js │ │ ├── palette.js │ │ ├── toolbar.js │ │ ├── sprite.js │ │ └── canvas.js ├── index.html └── tpl.js ├── libs ├── bootstrap │ ├── img │ │ ├── glyphicons-halflings.png │ │ └── glyphicons-halflings-white.png │ ├── css │ │ └── bootstrap-responsive.min.css │ └── js │ │ └── bootstrap.min.js ├── qunit │ └── qunit.css ├── store │ └── store.js └── modernizr │ └── modernizr-2.0.6.min.js ├── tasks ├── rebase.js └── git.js ├── .jshintrc ├── LICENSE ├── package.json ├── CONTRIBUTING.md ├── README.md ├── templates └── README.md └── Gruntfile.js /test/images/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/ok.png -------------------------------------------------------------------------------- /test/images/date.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/date.png -------------------------------------------------------------------------------- /test/images/gift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/gift.png -------------------------------------------------------------------------------- /test/images/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/help.png -------------------------------------------------------------------------------- /test/images/lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/lock.png -------------------------------------------------------------------------------- /test/images/love.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/love.png -------------------------------------------------------------------------------- /test/images/mail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/mail.png -------------------------------------------------------------------------------- /test/images/pin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/pin.png -------------------------------------------------------------------------------- /test/images/tool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/tool.png -------------------------------------------------------------------------------- /test/images/zoom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/zoom.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | amd/ 2 | dist/ 3 | doc/ 4 | node_modules/ 5 | stitches/ 6 | !build/stitches/ 7 | tmp/ -------------------------------------------------------------------------------- /src/img/stripes80.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/src/img/stripes80.gif -------------------------------------------------------------------------------- /src/img/stripes90.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/src/img/stripes90.gif -------------------------------------------------------------------------------- /src/img/test/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/src/img/test/github.png -------------------------------------------------------------------------------- /src/img/test/gmail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/src/img/test/gmail.png -------------------------------------------------------------------------------- /src/img/test/tumblr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/src/img/test/tumblr.png -------------------------------------------------------------------------------- /test/images/camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/camera.png -------------------------------------------------------------------------------- /test/images/cloud1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/cloud1.png -------------------------------------------------------------------------------- /test/images/cloud2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/cloud2.png -------------------------------------------------------------------------------- /test/images/cloud3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/cloud3.png -------------------------------------------------------------------------------- /test/images/cloud4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/cloud4.png -------------------------------------------------------------------------------- /test/images/config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/config.png -------------------------------------------------------------------------------- /test/images/file1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/file1.png -------------------------------------------------------------------------------- /test/images/file2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/file2.png -------------------------------------------------------------------------------- /test/images/file3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/file3.png -------------------------------------------------------------------------------- /test/images/file4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/file4.png -------------------------------------------------------------------------------- /test/images/gamepad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/gamepad.png -------------------------------------------------------------------------------- /test/images/garbage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/garbage.png -------------------------------------------------------------------------------- /test/images/letters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/letters.png -------------------------------------------------------------------------------- /test/images/monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/monitor.png -------------------------------------------------------------------------------- /test/images/notepad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/notepad.png -------------------------------------------------------------------------------- /test/images/phone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/phone.png -------------------------------------------------------------------------------- /test/images/picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/picture.png -------------------------------------------------------------------------------- /test/images/sound.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/sound.png -------------------------------------------------------------------------------- /test/images/unlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/unlock.png -------------------------------------------------------------------------------- /test/images/wallet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/wallet.png -------------------------------------------------------------------------------- /src/img/test/linkedin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/src/img/test/linkedin.png -------------------------------------------------------------------------------- /src/img/test/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/src/img/test/twitter.png -------------------------------------------------------------------------------- /test/images/openmail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/openmail.png -------------------------------------------------------------------------------- /test/images/suitcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/test/images/suitcase.png -------------------------------------------------------------------------------- /src/img/checkerboard10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/src/img/checkerboard10.png -------------------------------------------------------------------------------- /src/img/test/stackoverflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/src/img/test/stackoverflow.png -------------------------------------------------------------------------------- /libs/bootstrap/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/libs/bootstrap/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /src/templates/sprite.tpl: -------------------------------------------------------------------------------- 1 |
2 | 3 |
-------------------------------------------------------------------------------- /libs/bootstrap/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draeton/stitches/HEAD/libs/bootstrap/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /src/css/stitches.css: -------------------------------------------------------------------------------- 1 | @import url( "./base.css" ); 2 | @import url( "./toolbar.css" ); 3 | @import url( "./palette.css" ); 4 | @import url( "./sprite.css" ); -------------------------------------------------------------------------------- /test/unit/stitches.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | 3 | module("stitches"); 4 | 5 | test("test", function () { 6 | expect(1); 7 | ok(true, "test"); 8 | }); 9 | 10 | }(jQuery)); -------------------------------------------------------------------------------- /src/js/wrap/jquery.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # wrap/jquery 3 | * 4 | * Wrap global instance for use in RequireJS modules 5 | * 6 | * > http://draeton.github.io/stitches
7 | * > Copyright 2013 Matthew Cobbs
8 | * > Licensed under the MIT license. 9 | */ 10 | 11 | define(function () { 12 | "use strict"; 13 | return jQuery; 14 | }); -------------------------------------------------------------------------------- /src/templates/less-markup.tpl: -------------------------------------------------------------------------------- 1 | <% $.map(sprites, function (sprite) { %> 2 | <% if (tooltip) { %> 3 | 4 | <% } else { %> 5 | \n 6 | <% } %> 7 | <% }); %> -------------------------------------------------------------------------------- /src/js/wrap/modernizr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # wrap/modernizr 3 | * 4 | * Wrap global instance for use in RequireJS modules 5 | * 6 | * > http://draeton.github.io/stitches
7 | * > Copyright 2013 Matthew Cobbs
8 | * > Licensed under the MIT license. 9 | */ 10 | 11 | define(function () { 12 | "use strict"; 13 | return Modernizr; 14 | }); -------------------------------------------------------------------------------- /src/templates/css-markup.tpl: -------------------------------------------------------------------------------- 1 | <% $.map(sprites, function (sprite) { %> 2 | <% if (tooltip) { %> 3 | \n 4 | <% } else { %> 5 | \n 6 | <% } %> 7 | <% }); %> -------------------------------------------------------------------------------- /tasks/rebase.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | "use strict"; 4 | 5 | /** 6 | * register custom tasks 7 | */ 8 | 9 | grunt.registerMultiTask("rebase", "Rebase cwd", function () { 10 | var dir = this.data.dir; 11 | 12 | grunt.file.setBase(dir); 13 | grunt.log.ok("Base dir is now " + process.cwd()); 14 | }); 15 | }; -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": true, 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "unused": true, 11 | "boss": true, 12 | "eqnull": true, 13 | "node": true, 14 | "es5": true, 15 | "predef": [ 16 | "requirejs", 17 | "require", 18 | "define", 19 | "jQuery", 20 | "Modernizr" 21 | ] 22 | } -------------------------------------------------------------------------------- /src/templates/css.tpl: -------------------------------------------------------------------------------- 1 | .<%= prefix %> {\n 2 | background-image: url(<%= backgroundImage %>);\n 3 | background-repeat: no-repeat;\n 4 | display: block;\n 5 | }\n 6 | 7 | <% $.map(sprites, function (sprite) { %> 8 | \n 9 | .<%= prefix %>-<%= sprite.name %> {\n 10 | width: <%= sprite.image.width %>px;\n 11 | height: <%= sprite.image.height %>px;\n 12 | background-position: <%= sprite.left(true) %> <%= sprite.top(true) %>;\n 13 | }\n 14 | <% }); %> -------------------------------------------------------------------------------- /src/css/toolbar.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Stitches - HTML5 Sprite Generator 3 | * http://draeton.github.io/stitches 4 | * 5 | * Toolbar Module 6 | * 7 | * Copyright 2013 Matthew Cobbs 8 | * Licensed under the MIT license. 9 | */ 10 | 11 | .stitches-toolbar {} 12 | 13 | .stitches-toolbar button.files { 14 | position: relative; 15 | overflow: hidden; 16 | } 17 | 18 | .stitches-toolbar button.files input { 19 | position: absolute; 20 | top: 0; 21 | left: 10%; 22 | width: 80%; 23 | height: 100%; 24 | opacity: 0; 25 | } -------------------------------------------------------------------------------- /src/templates/less.tpl: -------------------------------------------------------------------------------- 1 | .stitches-<%= prefix %>(@x: 0, @y: 0, @width: 0, @height: 0) {\n 2 | background-position: @x @y;\n 3 | width: @width;\n 4 | height: @height;\n 5 | }\n 6 | \n 7 | .<%= prefix %> {\n 8 | background-image: url(<%= backgroundImage %>); 9 | background-repeat: no-repeat;\n 10 | display: block;\n 11 | <% $.map(sprites, function (sprite) { %> 12 | \n 13 | &.<%= prefix %>-<%= sprite.name %> {\n 14 | .stitches-<%= prefix %>(<%= sprite.left(true) %>, <%= sprite.top(true) %>, <%= sprite.image.width %>px, <%= sprite.image.height %>px);\n 15 | }\n 16 | <% }); %> 17 | }\n -------------------------------------------------------------------------------- /test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "immed": true, 5 | "latedef": true, 6 | "newcap": true, 7 | "noarg": true, 8 | "sub": true, 9 | "undef": true, 10 | "unused": true, 11 | "boss": true, 12 | "eqnull": true, 13 | "browser": true, 14 | "predef": [ 15 | "jQuery", 16 | "QUnit", 17 | "module", 18 | "test", 19 | "asyncTest", 20 | "expect", 21 | "start", 22 | "stop", 23 | "ok", 24 | "equal", 25 | "notEqual", 26 | "deepEqual", 27 | "notDeepEqual", 28 | "strictEqual", 29 | "notStrictEqual", 30 | "throws" 31 | ] 32 | } -------------------------------------------------------------------------------- /src/css/sprite.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Stitches - HTML5 Sprite Generator 3 | * http://draeton.github.io/stitches 4 | * 5 | * Sprite Module 6 | * 7 | * Copyright 2013 Matthew Cobbs 8 | * Licensed under the MIT license. 9 | */ 10 | 11 | .stitches-sprite { 12 | display: none; 13 | z-index: 0; 14 | position: absolute; 15 | cursor: pointer; 16 | } 17 | 18 | .stitches-sprite.placed { 19 | display: block; 20 | } 21 | 22 | .stitches-sprite:hover { 23 | z-index: 1; 24 | background-color: #e5e5e5; 25 | background-image: url(../img/stripes90.gif); 26 | } 27 | 28 | .stitches-sprite:hover img { 29 | opacity: 0.7; 30 | } 31 | 32 | .stitches-sprite.active { 33 | z-index: 2; 34 | } 35 | 36 | .stitches-sprite.active img { 37 | outline: 2px solid #3a87ad; 38 | } -------------------------------------------------------------------------------- /src/js/util/array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # util/array 3 | * 4 | * Utility methods for working with arrays 5 | * 6 | * > http://draeton.github.io/stitches
7 | * > Copyright 2013 Matthew Cobbs
8 | * > Licensed under the MIT license. 9 | */ 10 | 11 | define([ 12 | "wrap/jquery" 13 | ], 14 | function ($) { 15 | 16 | "use strict"; 17 | 18 | // **Module definition** 19 | return { 20 | /** 21 | * ### @remove 22 | * Remove from an array by value 23 | * 24 | * @param {array} list The array to filter 25 | * @param {*} value Any items matching value are removed 26 | * @return array 27 | */ 28 | remove: function (array, value) { 29 | return $(array).filter(function () { 30 | return this !== value; 31 | }); 32 | } 33 | }; 34 | 35 | }); -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Stitches Test Suite 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Matthew Cobbs 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/templates/downloads.tpl: -------------------------------------------------------------------------------- 1 | 2 | 8 |
9 |
10 |

11 |
12 |
13 |

14 |
15 |
16 |

17 |
18 |
19 | 20 |
<%= markupTooltip %>
21 | 22 |
23 |
-------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stitches", 3 | "title": "Stitches", 4 | "description": "Stitches is an HTML5 sprite sheet generator.", 5 | "version": "1.3.5", 6 | "homepage": "http://draeton.github.com/stitches/", 7 | "author": { 8 | "name": "Matthew Cobbs", 9 | "email": "draeton@gmail.com" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/draeton/stitches.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/draeton/stitches/issues" 17 | }, 18 | "licenses": [ 19 | { 20 | "type": "MIT", 21 | "url": "https://github.com/draeton/stitches/blob/master/LICENSE" 22 | } 23 | ], 24 | "devDependencies": { 25 | "grunt": "~0.4.0", 26 | "grunt-contrib-jshint": "~0.2.0", 27 | "grunt-contrib-qunit": "~0.2.0", 28 | "grunt-contrib-concat": "~0.1.3", 29 | "grunt-contrib-uglify": "~0.1.2", 30 | "grunt-contrib-requirejs": "~0.4.0", 31 | "grunt-replace": "~0.4.0", 32 | "grunt-contrib-cssmin": "~0.4.1", 33 | "grunt-contrib-copy": "~0.4.0", 34 | "grunt-zip": "~0.3.0", 35 | "grunt-contrib-clean": "~0.4.0", 36 | "grunt-bump": "0.0.2", 37 | "prompt": "~0.2.9", 38 | "grunt-docker": "0.0.4", 39 | "shelljs": "~0.1.2" 40 | }, 41 | "keywords": [ 42 | "stitches", 43 | "html5", 44 | "javascript", 45 | "sprite" 46 | ], 47 | "readmeFilename": "README.md", 48 | "baseBranch": "master" 49 | } 50 | -------------------------------------------------------------------------------- /src/js/stitches.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # Stitches 3 | * 4 | * ### _An HTML5 Sprite Sheet Generator_ 5 | * 6 | * > http://draeton.github.io/stitches
7 | * > Copyright 2013 Matthew Cobbs
8 | * > Licensed under the MIT license. 9 | * 10 | * Stitches is an HTML5 sprite sheet generator. 11 | * 12 | * Stitches is developed by Matthew Cobbs in concert with the lovely open-source 13 | * community at Github. Thanks are owed to the developers at Twitter for 14 | * [Bootstrap](http://twitter.github.io/bootstrap), and 15 | * [Glyphicons](http://glyphicons.com/) for some cool little icons. 16 | * 17 | * Addtionally, I want to thank [James Taylor](https://github.io/jbt) 18 | * for the [Docker](https://github.io/jbt/docker) documentation tool, and most 19 | * of all the good folks who develop [RequireJS](http://requirejs.org/) and 20 | * [GruntJS](http://gruntjs.com/), for helping this all make sense. 21 | */ 22 | 23 | /** 24 | * ### RequireJS Main 25 | * 26 | * Kicks off application on elements matching `.stitches` 27 | */ 28 | require({ 29 | paths: { 30 | "tpl" : "../tpl" 31 | } 32 | }, 33 | [ 34 | "wrap/jquery", 35 | "module/stitches" 36 | ], 37 | function($, Stitches) { 38 | 39 | "use strict"; 40 | 41 | $(document).ready(function () { 42 | 43 | var selector = ".stitches"; 44 | 45 | $(selector).each(function () { 46 | var stitches = new Stitches(this); 47 | }); 48 | }); 49 | 50 | }); -------------------------------------------------------------------------------- /src/js/stylesheet/css.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # stylesheet/css 3 | * 4 | * Base constructor for the CSS stylesheet manager 5 | * 6 | * > http://draeton.github.io/stitches
7 | * > Copyright 2013 Matthew Cobbs
8 | * > Licensed under the MIT license. 9 | */ 10 | 11 | define([ 12 | "wrap/jquery", 13 | "util/util", 14 | "util/templates", 15 | "stylesheet/base" 16 | ], 17 | function ($, util, templates, BaseStylesheet) { 18 | 19 | "use strict"; 20 | 21 | var defaults = { 22 | filename: "spritesheet.png" 23 | }; 24 | 25 | /** 26 | * ## CssStylesheet 27 | * Create a new `CssStylesheet` instance 28 | * 29 | * @constructor 30 | * @param {object} options 31 | */ 32 | var CssStylesheet = function (options) { 33 | this.settings = $.extend({}, defaults, options); 34 | }; 35 | 36 | util.inherit(CssStylesheet, BaseStylesheet, { 37 | template: templates.cssMarkup, 38 | 39 | /** 40 | * ### @get 41 | * Returns a stylesheet to place images with spritesheet 42 | * 43 | * @param {array} sprites A list of sprites 44 | * @param {string} spritesheet The data URL of the spritesheet 45 | * @param {string} prefix Used to create CSS classes 46 | * @param {boolean} uri Switch including image as data URI 47 | * @return string 48 | */ 49 | get: function (sprites, spritesheet, prefix, uri) { 50 | var backgroundImage = uri ? spritesheet : this.settings.filename; 51 | 52 | return templates.css({ 53 | prefix: prefix, 54 | backgroundImage: backgroundImage, 55 | sprites: sprites 56 | }); 57 | } 58 | }); 59 | 60 | return CssStylesheet; 61 | 62 | }); -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Important notes 4 | 5 | Please don't edit files in the `dist` subdirectory as they are generated via Grunt. You'll find source code in the `src` subdirectory! 6 | 7 | ### Code style 8 | 9 | Regarding code style like indentation and whitespace, **follow the conventions you see used in the source already.** 10 | 11 | ### PhantomJS 12 | 13 | While Grunt can run the included unit tests via [PhantomJS](http://phantomjs.org/), this shouldn't be considered a substitute for the real thing. Please be sure to test the `test/*.html` unit test file(s) in _actual_ browsers. 14 | 15 | ## Modifying the code 16 | 17 | First, ensure that you have the latest [Node.js](http://nodejs.org/) and [npm](http://npmjs.org/) installed. 18 | 19 | Test that Grunt's CLI is installed by running `grunt --version`. If the command isn't found, run `npm install -g grunt-cli`. For more information about installing Grunt, see the [getting started guide](http://gruntjs.com/getting-started). 20 | 21 | 1. Fork and clone the repo. 22 | 1. Run `npm install` to install all dependencies (including Grunt). 23 | 1. Run `grunt` to grunt this project. 24 | 25 | Assuming that you don't see any red, you're ready to go. Just be sure to run `grunt` after making any changes, to ensure that nothing is broken. 26 | 27 | ## Submitting pull requests 28 | 29 | 1. Create a new branch, please don't work in your `master` branch directly. 30 | 1. Add failing tests for the change you want to make. Run `grunt` to see the tests fail. 31 | 1. Fix stuff. 32 | 1. Run `grunt` to see if the tests pass. Repeat steps 2-4 until done. 33 | 1. Open `test/*.html` unit test file(s) in actual browser to ensure tests pass everywhere. 34 | 1. Update the documentation to reflect any changes. 35 | 1. Push to your fork and submit a pull request. 36 | -------------------------------------------------------------------------------- /src/js/stylesheet/less.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # stylesheet/less 3 | * 4 | * Base constructor for the LESS stylesheet manager 5 | * 6 | * > http://draeton.github.io/stitches
7 | * > Copyright 2013 Matthew Cobbs
8 | * > Licensed under the MIT license. 9 | */ 10 | 11 | define([ 12 | "wrap/jquery", 13 | "util/util", 14 | "util/templates", 15 | "stylesheet/base" 16 | ], 17 | function ($, util, templates, BaseStylesheet) { 18 | 19 | "use strict"; 20 | 21 | var defaults = { 22 | filename: "spritesheet.png" 23 | }; 24 | 25 | /** 26 | * ## LessStylesheet 27 | * Create a new `LessStylesheet` instance 28 | * 29 | * @constructor 30 | * @param {object} options 31 | */ 32 | var LessStylesheet = function (options) { 33 | this.settings = $.extend({}, defaults, options); 34 | }; 35 | 36 | util.inherit(LessStylesheet, BaseStylesheet, { 37 | template: templates.lessMarkup, 38 | 39 | /** 40 | * ### @get 41 | * Returns a stylesheet to place images with spritesheet 42 | * 43 | * @param {array} sprites A list of sprites 44 | * @param {string} spritesheet The data URL of the spritesheet 45 | * @param {string} prefix Used to create CSS classes 46 | * @param {boolean} uri Switch including image as data URI 47 | * @return string 48 | */ 49 | get: function (sprites, spritesheet, prefix, uri) { 50 | var backgroundImage = uri ? spritesheet : this.settings.filename; 51 | 52 | return templates.less({ 53 | prefix: prefix, 54 | backgroundImage: backgroundImage, 55 | sprites: sprites 56 | }); 57 | } 58 | }); 59 | 60 | return LessStylesheet; 61 | 62 | }); -------------------------------------------------------------------------------- /src/js/stylesheet/base.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # stylesheet/base 3 | * 4 | * Base constructor for the stylesheet managers 5 | * 6 | * > http://draeton.github.io/stitches
7 | * > Copyright 2013 Matthew Cobbs
8 | * > Licensed under the MIT license. 9 | */ 10 | 11 | define([ 12 | "wrap/jquery" 13 | ], 14 | function ($) { 15 | 16 | "use strict"; 17 | 18 | var defaults = { 19 | filename: "spritesheet.png" 20 | }; 21 | 22 | /** 23 | * ## BaseStylesheet 24 | * Create a new `BaseStylesheet` instance 25 | * 26 | * @constructor 27 | * @param {object} options 28 | */ 29 | var BaseStylesheet = function (options) { 30 | this.settings = $.extend({}, defaults, options); 31 | }; 32 | 33 | BaseStylesheet.prototype = { 34 | constructor: BaseStylesheet, 35 | 36 | template: null, 37 | 38 | /** 39 | * ### @get 40 | * Returns a stylesheet to place images with spritesheet 41 | * 42 | * @param {array} sprites A list of sprites 43 | * @param {string} spritesheet The data URL of the spritesheet 44 | * @param {string} prefix Used to create CSS classes 45 | * @param {boolean} uri Switch including image as data URI 46 | * @return string 47 | */ 48 | get: function (sprites, spritesheet, prefix, uri) {}, 49 | 50 | /** 51 | * ### @markup 52 | * Returns markup for spritesheet example usage 53 | * 54 | * @param {array} sprites A list of sprites 55 | * @param {string} prefix Used to create CSS classes 56 | * @param {boolean} tooltip If true display bootstrap tooltip 57 | * @return string 58 | */ 59 | markup: function (sprites, prefix, tooltip) { 60 | return this.template({ 61 | prefix: prefix, 62 | sprites: sprites, 63 | tooltip: tooltip 64 | }); 65 | } 66 | }; 67 | 68 | return BaseStylesheet; 69 | 70 | }); -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Stitches 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 |
39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 |
47 |
48 |
49 | 50 | -------------------------------------------------------------------------------- /src/css/base.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Stitches - HTML5 Sprite Generator 3 | * http://draeton.github.io/stitches 4 | * 5 | * HTML5 Sprite Sheet Generator 6 | * 7 | * Copyright 2013 Matthew Cobbs 8 | * Licensed under the MIT license. 9 | */ 10 | 11 | .stitches { 12 | min-width: 400px; 13 | } 14 | 15 | .stitches > img { 16 | display: none; 17 | } 18 | 19 | .stitches-toolbar { 20 | margin: 0; 21 | padding: 6px; 22 | background-color: #fafafa; 23 | background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2); 24 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2)); 25 | background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); 26 | background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); 27 | background-image: linear-gradient(to bottom, #ffffff, #f2f2f2); 28 | background-repeat: repeat-x; 29 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); 30 | *zoom: 1; 31 | border: 1px solid #d4d4d4; 32 | -webkit-border-radius: 4px 4px 0 0; 33 | -moz-border-radius: 4px 4px 0 0; 34 | border-radius: 4px 4px 0 0; 35 | } 36 | 37 | .stitches-progress { 38 | height: 4px; 39 | background-color: #e5e5e5; 40 | } 41 | 42 | .stitches-progress .progress { 43 | margin: 0; 44 | -webkit-border-radius: 0; 45 | -moz-border-radius: 0; 46 | border-radius: 0; 47 | } 48 | 49 | .stitches-drop-box { 50 | position: relative; 51 | z-index: 0; 52 | min-height: 400px; 53 | } 54 | 55 | .stitches-overlay { 56 | display: none; 57 | position: absolute; 58 | z-index: 1000; 59 | width: 100%; 60 | height: 100%; 61 | background-color: #e5e5e5; 62 | background-image: url(../img/stripes90.gif); 63 | } 64 | 65 | .stitches-overlay.in { 66 | opacity: 0.4; 67 | } 68 | 69 | .stitches-wrap { 70 | position: absolute; 71 | z-index: 0; 72 | width: 100%; 73 | height: 100%; 74 | background-color: #e5e5e5; 75 | overflow: auto; 76 | } 77 | 78 | .stitches-canvas { 79 | position: relative; 80 | z-index: 0; 81 | width: 0; 82 | height: 0; 83 | background-image: url(../img/checkerboard10.png); 84 | } -------------------------------------------------------------------------------- /tasks/git.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 3 | "use strict"; 4 | 5 | /** 6 | * register custom tasks 7 | */ 8 | 9 | 10 | /** 11 | * git checkout 12 | */ 13 | grunt.registerMultiTask("checkout", "Checkout a git branch", function () { 14 | var done = this.async(); 15 | var shell = require("shelljs"); 16 | var pkg = require("../package.json"); 17 | var branch = this.data.branch || "master"; 18 | 19 | shell.exec("git checkout " + branch, function () { 20 | done(); 21 | }); 22 | }); 23 | 24 | /** 25 | * git add . && git commit -am "" && git push 26 | */ 27 | var commitMessage = ""; 28 | 29 | var setCommitMessage = function (callback) { 30 | var prompt = require("prompt"); 31 | 32 | if (!commitMessage) { 33 | grunt.log.writeln("Please enter a commit message."); 34 | prompt.start(); 35 | prompt.get(["msg"], function (err, result) { 36 | if (err || !result.msg) { 37 | grunt.fail.fatal("This task requires a message."); 38 | } 39 | 40 | commitMessage = result.msg; 41 | callback && callback(); 42 | }); 43 | } else { 44 | callback && callback(); 45 | } 46 | }; 47 | 48 | grunt.registerMultiTask("push", "Commit the changes and push to github", function () { 49 | var done = this.async(); 50 | var shell = require("shelljs"); 51 | var pkg = require("../package.json"); 52 | var branch = this.data.branch || "master"; 53 | var messagePrefix; 54 | 55 | switch (branch) { 56 | case "gh-pages": 57 | messagePrefix = "Pages " + pkg.version + " - "; 58 | break; 59 | case "master": 60 | default: 61 | messagePrefix = "Build " + pkg.version + " - "; 62 | break; 63 | } 64 | 65 | setCommitMessage(function () { 66 | shell.exec("git add ."); 67 | shell.exec("git commit -am \"" + messagePrefix + commitMessage + "\""); 68 | shell.exec("git push origin " + branch, function () { 69 | done(); 70 | }); 71 | }); 72 | }); 73 | }; -------------------------------------------------------------------------------- /src/js/util/templates.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # util/templates 3 | * 4 | * Utility methods for referencing js templates 5 | * 6 | * > http://draeton.github.io/stitches
7 | * > Copyright 2013 Matthew Cobbs
8 | * > Licensed under the MIT license. 9 | */ 10 | 11 | define([ 12 | "tpl!../../templates/stitches.tpl", 13 | "tpl!../../templates/downloads.tpl", 14 | "tpl!../../templates/sprite.tpl", 15 | "tpl!../../templates/css.tpl", 16 | "tpl!../../templates/css-markup.tpl", 17 | "tpl!../../templates/less.tpl", 18 | "tpl!../../templates/less-markup.tpl" 19 | ], 20 | function (stitchesTemplate, downloadsTemplate, spriteTemplate, cssTemplate, cssMarkupTemplate, lessTemplate, lessMarkupTemplate) { 21 | 22 | "use strict"; 23 | 24 | // **Module definition** 25 | return { 26 | /** 27 | * ### @stitches 28 | * Returns the app template 29 | * 30 | * @return string 31 | */ 32 | stitches: function () { 33 | return stitchesTemplate.apply(this, arguments); 34 | }, 35 | 36 | /** 37 | * ### @downloads 38 | * Returns the downloads template 39 | * 40 | * @return string 41 | */ 42 | downloads: function () { 43 | return downloadsTemplate.apply(this, arguments); 44 | }, 45 | 46 | /** 47 | * ### @sprite 48 | * Returns the sprite template 49 | * 50 | * @return string 51 | */ 52 | sprite: function () { 53 | return spriteTemplate.apply(this, arguments); 54 | }, 55 | 56 | /** 57 | * ### @css 58 | * Returns the css template 59 | * 60 | * @return string 61 | */ 62 | css: function () { 63 | return cssTemplate.apply(this, arguments); 64 | }, 65 | 66 | /** 67 | * ### @cssMarkup 68 | * Returns the css markup template 69 | * 70 | * @return string 71 | */ 72 | cssMarkup: function () { 73 | return cssMarkupTemplate.apply(this, arguments); 74 | }, 75 | 76 | /** 77 | * ### @less 78 | * Returns the less template 79 | * 80 | * @return string 81 | */ 82 | less: function () { 83 | return lessTemplate.apply(this, arguments); 84 | }, 85 | 86 | /** 87 | * ### @lessMarkup 88 | * Returns the less markup template 89 | * 90 | * @return string 91 | */ 92 | lessMarkup: function () { 93 | return lessMarkupTemplate.apply(this, arguments); 94 | } 95 | }; 96 | 97 | }); -------------------------------------------------------------------------------- /src/js/manager/stylesheet.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # manager/stylesheet 3 | * 4 | * Methods for setting the canvas stylesheet type and making the stylesheets 5 | * 6 | * > http://draeton.github.io/stitches
7 | * > Copyright 2013 Matthew Cobbs
8 | * > Licensed under the MIT license. 9 | */ 10 | 11 | define([ 12 | "wrap/jquery", 13 | "stylesheet/css", 14 | "stylesheet/less" 15 | ], 16 | function ($, CssStylesheet, LessStylesheet) { 17 | 18 | "use strict"; 19 | 20 | // **Canvas stylesheet managers** 21 | var managers = { 22 | css: CssStylesheet, 23 | less: LessStylesheet 24 | }; 25 | 26 | // **Module definition** 27 | return { 28 | /** 29 | * ### @set 30 | * Set the working stylesheet manager instance by type 31 | * 32 | * @param {string} type The stylesheet manager type 33 | */ 34 | set: function (type) { 35 | var Manager; 36 | 37 | this.type = type || "css"; 38 | Manager = managers[this.type]; 39 | this.manager = new Manager(); 40 | }, 41 | 42 | /** 43 | * ### @getStylesheet 44 | * Returns a stylesheet to place images with spritesheet 45 | * 46 | * @param {array} options.sprites A list of sprites 47 | * @param {string} options.spritesheet The data URL of the spritesheet 48 | * @param {string} options.prefix Used to create CSS classes 49 | * @param {boolean} options.uri Switch including image as data URI 50 | * @return string 51 | */ 52 | getStylesheet: function (options) { 53 | var sprites = options.sprites; 54 | var spritesheet = options.spritesheet; 55 | var prefix = options.prefix; 56 | var uri = options.uri; 57 | 58 | var styles = this.manager.get(sprites, spritesheet, prefix, uri); 59 | styles = styles.replace(/\\n/g, "\n"); 60 | 61 | return styles; 62 | }, 63 | 64 | /** 65 | * ### @getMarkup 66 | * Returns markup for spritesheet example usage 67 | * 68 | * @param {array} options.sprites A list of sprites 69 | * @param {string} options.prefix Used to create CSS classes 70 | * @return string 71 | */ 72 | getMarkup: function (options) { 73 | var sprites = options.sprites; 74 | var prefix = options.prefix; 75 | var tooltip = options.tooltip || false; 76 | 77 | var markup = this.manager.markup(sprites, prefix, tooltip); 78 | markup = markup.replace(/\\n/g, "\n"); 79 | 80 | return markup; 81 | } 82 | }; 83 | 84 | }); -------------------------------------------------------------------------------- /src/js/util/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # util/util 3 | * 4 | * This is the home for wayward methods who have lost their way. 5 | * 6 | * > http://draeton.github.io/stitches
7 | * > Copyright 2013 Matthew Cobbs
8 | * > Licensed under the MIT license. 9 | */ 10 | 11 | define([ 12 | "wrap/jquery" 13 | ], 14 | function ($) { 15 | 16 | "use strict"; 17 | 18 | // **Module definition** 19 | return { 20 | /** 21 | * ### @inherit 22 | * Set up prototypical inheritance 23 | * 24 | * @param {function} Child Constructor 25 | * @param {function} Parent Constructor 26 | * @param {object} methods To add to Child.prototype 27 | */ 28 | inherit: function (Child, Parent, methods) { 29 | Child.prototype = new Parent(); 30 | Child.prototype.constructor = Parent; 31 | 32 | $.each(methods, function (name, method) { 33 | Child.prototype[name] = method; 34 | }); 35 | 36 | Child.prototype._super = function (name, context, args) { 37 | var method = Parent.prototype[name]; 38 | 39 | return method.apply(context, args); 40 | }; 41 | }, 42 | 43 | /** 44 | * ### @debounce 45 | * Prevent a function from being called more than once within 46 | * a certain threshold 47 | * 48 | * @param {function} func Function to modify 49 | * @param {number} threshold In ms 50 | * @param {boolean} execAsap If true, run function on first call 51 | * @return function 52 | */ 53 | debounce: function (func, threshold, execAsap) { 54 | var timeout; 55 | 56 | return function () { 57 | var context = this; 58 | var args = arguments; 59 | 60 | var delayed = function () { 61 | if (!execAsap) { 62 | func.apply(context, args); 63 | } 64 | 65 | timeout = null; 66 | }; 67 | 68 | if (timeout) { 69 | window.clearTimeout(timeout); 70 | } else if (execAsap) { 71 | func.apply(context, args); 72 | } 73 | 74 | timeout = setTimeout(delayed, threshold || 50); 75 | }; 76 | }, 77 | 78 | /** 79 | * ### @noop 80 | * No operation 81 | * 82 | * @param {event} e Optional 83 | */ 84 | noop: function (e) { 85 | if (e) { 86 | e.preventDefault(); 87 | e.stopPropagation(); 88 | } 89 | }, 90 | 91 | /** 92 | * ### @toPx 93 | * Convet a number to px for stylesheets 94 | * 95 | * @param {string} num Pixel value 96 | * @return string 97 | */ 98 | toPx: function (num) { 99 | return num ? num + "px" : "0"; 100 | } 101 | }; 102 | 103 | }); -------------------------------------------------------------------------------- /src/css/palette.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Stitches - HTML5 Sprite Generator 3 | * http://draeton.github.io/stitches 4 | * 5 | * Palette Module 6 | * 7 | * Copyright 2013 Matthew Cobbs 8 | * Licensed under the MIT license. 9 | */ 10 | 11 | .stitches-palette { 12 | display: none; 13 | position: absolute; 14 | top: 10px; 15 | right: 10px; 16 | width: 480px; 17 | background-color: #fafafa; 18 | background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2); 19 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2)); 20 | background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); 21 | background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); 22 | background-image: linear-gradient(to bottom, #ffffff, #f2f2f2); 23 | background-repeat: repeat-x; 24 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); 25 | *zoom: 1; 26 | border: 1px solid #d4d4d4; 27 | -webkit-border-radius: 4px 4px 0 0; 28 | -moz-border-radius: 4px 4px 0 0; 29 | border-radius: 4px 4px 0 0; 30 | } 31 | 32 | .stitches-palette.fade.in { 33 | display: block; 34 | opacity: 1; 35 | } 36 | 37 | .stitches-palette-header { 38 | padding: 0 15px; 39 | border-bottom: 1px solid #eee; 40 | } 41 | 42 | .stitches-palette-body { 43 | padding: 9px 15px; 44 | } 45 | 46 | .stitches-palette-body form { 47 | margin: 0; 48 | } 49 | 50 | .stitches-palette-body textarea { 51 | font-family: "Courier New", Courier, monospace; 52 | width: 100%; 53 | -webkit-box-sizing: border-box; 54 | -moz-box-sizing: border-box; 55 | box-sizing: border-box; 56 | } 57 | 58 | .stitches-palette-body .form-horizontal .control-group { 59 | margin-bottom: 10px; 60 | } 61 | 62 | .stitches-palette-body .form-horizontal .control-group:last-child { 63 | margin-bottom: 0; 64 | } 65 | 66 | .stitches-palette-body .form-horizontal .control-label { 67 | width: 120px; 68 | font-size: 12px; 69 | } 70 | 71 | .stitches-palette-body .form-horizontal .controls { 72 | margin-left: 140px; 73 | } 74 | 75 | @media (max-width: 480px) { 76 | .stitches-palette-body .form-horizontal .control-label { 77 | width: auto; 78 | } 79 | 80 | .stitches-palette-body .form-horizontal .controls { 81 | margin-left: 0; 82 | } 83 | 84 | .stitches-palette-body img { 85 | max-width: 150px; 86 | } 87 | } 88 | 89 | .stitches-palette-footer { 90 | padding: 0 15px; 91 | border-top: 1px solid #ddd; 92 | } 93 | 94 | .stitches-palette-footer .btn-toolbar { 95 | float: right; 96 | } 97 | 98 | /** downloads */ 99 | 100 | .stitches-downloads { 101 | width: 600px; 102 | } 103 | 104 | .stitches-downloads .stitches-palette-body { 105 | max-height: 250px; 106 | overflow: auto; 107 | } 108 | 109 | .stitches-downloads .stitches-example i { 110 | float: left; 111 | margin: 6px; 112 | } 113 | 114 | /** responsive */ 115 | 116 | @media (max-width: 767px) { 117 | .stitches-palette { 118 | top: 0; 119 | right: 0; 120 | width: 100%; 121 | border-left: 0; 122 | border-right: 0; 123 | } 124 | } -------------------------------------------------------------------------------- /src/js/layout/base.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # layout/base 3 | * 4 | * Base constructor for the canvas layout managers. Used to determine 5 | * canvas dimensions and to place sprites without intersections (overlap) 6 | * 7 | * > http://draeton.github.io/stitches
8 | * > Copyright 2013 Matthew Cobbs
9 | * > Licensed under the MIT license. 10 | */ 11 | 12 | define([ 13 | "wrap/jquery" 14 | ], 15 | function ($) { 16 | 17 | "use strict"; 18 | 19 | var defaults = { 20 | maxPass: 2 // number of tries to place sprite 21 | }; 22 | 23 | /** 24 | * ## BaseLayout 25 | * Create a new `BaseLayout` instance 26 | * 27 | * @constructor 28 | * @param {object} options 29 | */ 30 | var BaseLayout = function (options) { 31 | this.settings = $.extend({}, defaults, options); 32 | }; 33 | 34 | // **Prototype** 35 | BaseLayout.prototype = { 36 | constructor: BaseLayout, 37 | 38 | /** 39 | * ### @getDimensions 40 | * Returns an object with the width and height necessary 41 | * to contain the `sprites` 42 | * 43 | * @param {array} sprites The list of sprites to size for 44 | * @param {object} defaults Default width and height, if no sprites 45 | * @return object 46 | */ 47 | getDimensions: function (sprites, defaults) {}, 48 | 49 | /** 50 | * ### @placeSprite 51 | * Determine sprite coordinates on the canvas. Once a position is 52 | * determined with no intersections, the sprite is added to the 53 | * placed array. If there is no space, the dimensions are updated. 54 | * 55 | * @param {Sprite} sprite The sprite to place 56 | * @param {array} placed An array of sprites already placed 57 | * @param {object} dimensions The current canvas dimensions 58 | */ 59 | placeSprite: function (sprite, placed, dimensions) {}, 60 | 61 | /** 62 | * ### @intersection 63 | * Determine if a sprite intersects any other placed sprites. If no, 64 | * returns undefined; if yes, returns the intersecting sprite 65 | * for comparison 66 | * 67 | * @param {Sprite} sprite The sprite to compare against others 68 | * @param {array} obstacles An array of sprites already placed 69 | * @return undefined|Sprite 70 | */ 71 | intersection: function (sprite, obstacles) { 72 | var x1, x2, y1, y2; 73 | var intersections = []; 74 | var intersection; 75 | 76 | $.map(obstacles, function (obstacle) { 77 | x1 = (obstacle.x < (sprite.x + sprite.width)); 78 | y1 = (obstacle.y < (sprite.y + sprite.height)); 79 | x2 = ((obstacle.x + obstacle.width) > sprite.x); 80 | y2 = ((obstacle.y + obstacle.height) > sprite.y); 81 | 82 | if (x1 && x2 && y1 && y2) { 83 | intersections.push(obstacle); 84 | } 85 | }); 86 | 87 | if (intersections.length) { 88 | intersection = intersections.pop(); 89 | } 90 | 91 | return intersection; 92 | } 93 | }; 94 | 95 | return BaseLayout; 96 | 97 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [Stitches](http://draeton.github.com/stitches/) 2 | ========== 3 | 4 | Stitches is an HTML5 sprite sheet generator. 5 | The current version is `1.3.5`. Documentation is available 6 | [here](http://draeton.github.com/stitches/stitches/doc/stitches.js.html). 7 | 8 | ## Implementation 9 | 10 | After dependencies, Stitches requires a stylesheet, a script, and an HTML element to get the job done: 11 | 12 | ```html 13 | 14 | 15 | 16 | ``` 17 | 18 | The sprite sheet generator is automatically created in elements that have the `stitches` class: 19 | 20 | ```html 21 |
22 | ``` 23 | 24 | If you choose, any images that are a part of the initial markup will be loaded onto the canvas: 25 | 26 | ```html 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | ``` 36 | 37 | ## Dependencies 38 | 39 | [jQuery 1.7.1](http://jquery.com/), [Modernizr 2.0.6](http://modernizr.com/), [Bootstrap 2.3.0](http://twitter.github.com/bootstrap/) 40 | 41 | ```html 42 | 43 | 44 | 45 | 46 | 47 | 48 | ``` 49 | 50 | ## Download 51 | 52 | **The latest release, 1.3.5, is [available here](http://draeton.github.com/stitches/stitches/dist/stitches-1.3.5.zip).** 53 | 54 | 55 | ## Contributors 56 | 57 | * [amenadiel](https://github.com/amenadiel) 58 | * [egeriis](https://github.com/egeriis) 59 | * [flying-sheep](https://github.com/flying-sheep) 60 | * [JonDum](https://github.com/JonDum) 61 | * [mreq](https://github.com/mreq) 62 | 63 | 64 | ## License 65 | 66 | (The MIT License) 67 | 68 | Copyright (c) 2013 [Matthew Cobbs](mailto:draeton@gmail.com) 69 | 70 | Permission is hereby granted, free of charge, to any person obtaining 71 | a copy of this software and associated documentation files (the 72 | "Software"), to deal in the Software without restriction, including 73 | without limitation the rights to use, copy, modify, merge, publish, 74 | distribute, sublicense, and/or sell copies of the Software, and to 75 | permit persons to whom the Software is furnished to do so, subject to 76 | the following conditions: 77 | 78 | The above copyright notice and this permission notice shall be included 79 | in all copies or substantial portions of the Software. 80 | 81 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 82 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 83 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 84 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 85 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 86 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 87 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 88 | -------------------------------------------------------------------------------- /src/js/manager/file.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # manager/file 3 | * 4 | * Methods for loading files to the canvas and giving updates on their 5 | * progress 6 | * 7 | * > http://draeton.github.io/stitches
8 | * > Copyright 2013 Matthew Cobbs
9 | * > Licensed under the MIT license. 10 | */ 11 | 12 | define([ 13 | "wrap/jquery", 14 | "util/util" 15 | ], 16 | function ($, util) { 17 | 18 | "use strict"; 19 | 20 | // **Module definition** 21 | return { 22 | total: 0, // total count of files 23 | processed: 0, // total count of processed files 24 | queue: [], // queue after reading; used to process 25 | 26 | /** 27 | * ### file.set 28 | * Set the file manager handlers 29 | * 30 | * @param {object} handlers The handlers for various events 31 | */ 32 | set: function (handlers) { 33 | handlers = handlers || {}; 34 | 35 | this.onload = handlers.onload || util.noop; 36 | this.onprogress = handlers.onprogress || util.noop; 37 | this.onerror = handlers.onerror || util.noop; 38 | }, 39 | 40 | /** 41 | * ### @processFiles 42 | * Reset the queue and start processing a list of files 43 | * 44 | * @param {array} files An array of files from one of the file inputs 45 | */ 46 | processFiles: function (files) { 47 | var self = this; 48 | 49 | this.total = files.length; 50 | this.processed = 0; 51 | this.queue = []; 52 | 53 | $.map(files, function (file) { 54 | if (/jpeg|png|gif/.test(file.type)) { 55 | self.processFile(file); 56 | } 57 | }); 58 | 59 | this.onprogress(0, "info"); 60 | }, 61 | 62 | /** 63 | * ### @processFile 64 | * Use the FileReader to read in image files from input, and add 65 | * them to the queue. When all files are read, the queue is then 66 | * processed 67 | * 68 | * @param {object} file From a file input 69 | */ 70 | processFile: function (file) { 71 | var self = this; 72 | var reader; 73 | 74 | try { 75 | reader = new FileReader(); 76 | reader.onloadend = function (e) { 77 | var name = file.name; 78 | var src = e.target.result; 79 | var progress = ++self.processed / self.total; 80 | 81 | self.onprogress(progress); 82 | self.queue.push([name, src]); 83 | 84 | if (self.queue.length === self.total) { 85 | self.processQueue(); 86 | } 87 | }; 88 | reader.readAsDataURL(file); 89 | } catch (e) { 90 | this.onerror(e); 91 | } 92 | }, 93 | 94 | /** 95 | * ### @processQueue 96 | * Loop over the queue and apply the onload callback to each 97 | * item 98 | */ 99 | processQueue: function () { 100 | var self = this; 101 | 102 | $.map(this.queue, function (args) { 103 | self.onload.apply(self, args); 104 | }); 105 | } 106 | }; 107 | 108 | }); -------------------------------------------------------------------------------- /templates/README.md: -------------------------------------------------------------------------------- 1 | [Stitches](http://draeton.github.com/stitches/) 2 | ========== 3 | 4 | Stitches is an HTML5 sprite sheet generator. 5 | The current version is `@@version`. Documentation is available 6 | [here](http://draeton.github.com/stitches/stitches/doc/stitches.js.html). 7 | 8 | ## Implementation 9 | 10 | After dependencies, Stitches requires a stylesheet, a script, and an HTML element to get the job done: 11 | 12 | ```html 13 | 14 | 15 | 16 | ``` 17 | 18 | The sprite sheet generator is automatically created in elements that have the `stitches` class: 19 | 20 | ```html 21 |
22 | ``` 23 | 24 | If you choose, any images that are a part of the initial markup will be loaded onto the canvas: 25 | 26 | ```html 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | ``` 36 | 37 | ## Dependencies 38 | 39 | [jQuery 1.7.1](http://jquery.com/), [Modernizr 2.0.6](http://modernizr.com/), [Bootstrap 2.3.0](http://twitter.github.com/bootstrap/) 40 | 41 | ```html 42 | 43 | 44 | 45 | 46 | 47 | 48 | ``` 49 | 50 | ## Download 51 | 52 | **The latest release, @@version, is [available here](http://draeton.github.com/stitches/stitches/dist/stitches-@@version.zip).** 53 | 54 | 55 | ## Contributors 56 | 57 | * [amenadiel](https://github.com/amenadiel) 58 | * [egeriis](https://github.com/egeriis) 59 | * [flying-sheep](https://github.com/flying-sheep) 60 | * [JonDum](https://github.com/JonDum) 61 | * [mreq](https://github.com/mreq) 62 | 63 | 64 | ## License 65 | 66 | (The MIT License) 67 | 68 | Copyright (c) 2013 [Matthew Cobbs](mailto:draeton@gmail.com) 69 | 70 | Permission is hereby granted, free of charge, to any person obtaining 71 | a copy of this software and associated documentation files (the 72 | "Software"), to deal in the Software without restriction, including 73 | without limitation the rights to use, copy, modify, merge, publish, 74 | distribute, sublicense, and/or sell copies of the Software, and to 75 | permit persons to whom the Software is furnished to do so, subject to 76 | the following conditions: 77 | 78 | The above copyright notice and this permission notice shall be included 79 | in all copies or substantial portions of the Software. 80 | 81 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 82 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 83 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 84 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 85 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 86 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 87 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 88 | -------------------------------------------------------------------------------- /src/js/module/drop-box.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # module/drop-box 3 | * 4 | * Constructor for the drag and drop element. Used to allow users to drag 5 | * files onto a DOM element to initiate processing 6 | * 7 | * > http://draeton.github.io/stitches
8 | * > Copyright 2013 Matthew Cobbs
9 | * > Licensed under the MIT license. 10 | */ 11 | 12 | define([ 13 | "wrap/jquery", 14 | "util/util" 15 | ], 16 | function($, util) { 17 | 18 | "use strict"; 19 | 20 | var defaults = {}; 21 | 22 | /** 23 | * ## DropBox 24 | * Create a new `DropBox` instance 25 | * 26 | * @constructor 27 | * @param {element} element 28 | * @param {object} options 29 | */ 30 | var DropBox = function (element, options) { 31 | this.$element = $(element); 32 | this.$overlay = this.$element.find(".stitches-overlay"); 33 | this.settings = $.extend({}, defaults, options); 34 | 35 | this.init(); 36 | }; 37 | 38 | DropBox.classname = ".stitches-drop-box"; 39 | 40 | DropBox.prototype = { 41 | constructor: DropBox, 42 | 43 | /** 44 | * ### @init 45 | * Run methods to prepare the instance for use 46 | */ 47 | init: function () { 48 | this.bind(); 49 | }, 50 | 51 | /** 52 | * ### @bind 53 | * Bind event handlers to DOM element. $.proxy is used to retain 54 | * this instance as the callback execution context 55 | */ 56 | bind: function () { 57 | var dropBox = this.$element.get(0); 58 | var overlay = this.$overlay.get(0); 59 | 60 | dropBox.addEventListener("dragenter", $.proxy(this.dragStart, this), false); 61 | overlay.addEventListener("dragleave", $.proxy(this.dragStop, this), false); 62 | overlay.addEventListener("dragexit", $.proxy(this.dragStop, this), false); 63 | overlay.addEventListener("dragover", util.noop, false); 64 | overlay.addEventListener("drop", $.proxy(this.drop, this), false); 65 | }, 66 | 67 | /** 68 | * ### @dragStart 69 | * Close all palettes and block the UI when dragging 70 | * 71 | * @param {event} e The event object 72 | */ 73 | dragStart: function (e) { 74 | this.$element.trigger("close-palettes"); 75 | this.$element.trigger("show-overlay"); 76 | }, 77 | 78 | /** 79 | * ### @dragStop 80 | * If we're on the target, unblock the UI 81 | * 82 | * @param {event} e The event object 83 | */ 84 | dragStop: function (e) { 85 | if ($.contains(this.$element, e.target)) { 86 | this.$element.trigger("hide-overlay"); 87 | } 88 | }, 89 | 90 | /** 91 | * ### @drop 92 | * When a drop event occurs, check for files. If there 93 | * are files, start processing them 94 | * 95 | * @param {event} e The event object 96 | */ 97 | drop: function (e) { 98 | var files = (e.files || e.dataTransfer.files); 99 | 100 | e.stopPropagation(); 101 | e.preventDefault(); 102 | 103 | if (files.length) { 104 | this.$element.trigger("process-files", [files]); 105 | } else { 106 | this.$element.trigger("hide-overlay"); 107 | } 108 | } 109 | }; 110 | 111 | return DropBox; 112 | 113 | }); -------------------------------------------------------------------------------- /src/js/layout/vertical.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # layout/vertical 3 | * 4 | * Constructor for the vertical canvas layout manager. Used to determine 5 | * canvas dimensions and to place sprites without intersections (overlap). 6 | * Places sprites in a vertical column 7 | * 8 | * > http://draeton.github.io/stitches
9 | * > Copyright 2013 Matthew Cobbs
10 | * > Licensed under the MIT license. 11 | */ 12 | 13 | define([ 14 | "wrap/jquery", 15 | "util/util", 16 | "layout/base" 17 | ], 18 | function ($, util, BaseLayout) { 19 | 20 | "use strict"; 21 | 22 | var defaults = { 23 | maxPass: 2 // number of tries to place sprite 24 | }; 25 | 26 | /** 27 | * ## VerticalLayout 28 | * Create a new `VerticalLayout` instance 29 | * 30 | * @constructor 31 | * @param {object} options 32 | */ 33 | var VerticalLayout = function (options) { 34 | this.settings = $.extend({}, defaults, options); 35 | }; 36 | 37 | util.inherit(VerticalLayout, BaseLayout, { 38 | /** 39 | * ### @getDimensions 40 | * Returns an object with the width and height necessary 41 | * to contain the `sprites`. Calculation based on adding all of the 42 | * sprite heights. 43 | * 44 | * @param {array} sprites The list of sprites to size for 45 | * @param {object} defaults Default width and height, if no sprites 46 | * @return object 47 | */ 48 | getDimensions: function (sprites, defaults) { 49 | var width = 0; 50 | var height = 0; 51 | 52 | $.map(sprites, function (sprite) { 53 | width = sprite.width > width ? sprite.width : width; 54 | height += sprite.height; 55 | }); 56 | 57 | return { 58 | width: width || defaults.width, 59 | height: height || defaults.height 60 | }; 61 | }, 62 | 63 | /** 64 | * ### @placeSprite 65 | * Determine sprite coordinates on the canvas. Once a position is 66 | * determined with no intersections, the sprite is added to the 67 | * placed array. If there is no space, the dimensions are updated. 68 | * Seeks down to place the sprite. 69 | * 70 | * @param {Sprite} sprite The sprite to place 71 | * @param {array} placed An array of sprites already placed 72 | * @param {object} dimensions The current canvas dimensions 73 | */ 74 | placeSprite: function (sprite, placed, dimensions) { 75 | var intersection; 76 | var pass = 0; 77 | var x = 0; 78 | var y = 0; 79 | 80 | while (pass++ < this.settings.maxPass) { 81 | for (y = 0; y <= dimensions.height - sprite.height; y++) { 82 | sprite.x = x; 83 | sprite.y = y; 84 | 85 | intersection = this.intersection(sprite, placed); 86 | 87 | if (!intersection) { 88 | placed.push(sprite); 89 | sprite.show(); 90 | return true; 91 | } 92 | 93 | y = intersection.y + intersection.height - 1; 94 | } 95 | 96 | dimensions.width += sprite.width; 97 | dimensions.height += sprite.height; 98 | } 99 | 100 | return false; 101 | } 102 | }); 103 | 104 | return VerticalLayout; 105 | 106 | }); 107 | -------------------------------------------------------------------------------- /src/js/layout/horizontal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # layout/horizontal 3 | * 4 | * Constructor for the horizontal canvas layout manager. Used to determine 5 | * canvas dimensions and to place sprites without intersections (overlap). 6 | * Places sprites in a horizontal row 7 | * 8 | * > http://draeton.github.io/stitches
9 | * > Copyright 2013 Matthew Cobbs
10 | * > Licensed under the MIT license. 11 | */ 12 | 13 | define([ 14 | "wrap/jquery", 15 | "util/util", 16 | "layout/base" 17 | ], 18 | function ($, util, BaseLayout) { 19 | 20 | "use strict"; 21 | 22 | var defaults = { 23 | maxPass: 2 // number of tries to place sprite 24 | }; 25 | 26 | /** 27 | * ## HorizontalLayout 28 | * Create a new `HorizontalLayout` instance 29 | * 30 | * @constructor 31 | * @param {object} options 32 | */ 33 | var HorizontalLayout = function (options) { 34 | this.settings = $.extend({}, defaults, options); 35 | }; 36 | 37 | util.inherit(HorizontalLayout, BaseLayout, { 38 | /** 39 | * ### @getDimensions 40 | * Returns an object with the width and height necessary 41 | * to contain the `sprites`. Calculation based on adding all of 42 | * the spirte widths. 43 | * 44 | * @param {array} sprites The list of sprites to size for 45 | * @param {object} defaults Default width and height, if no sprites 46 | * @return object 47 | */ 48 | getDimensions: function (sprites, defaults) { 49 | var width = 0; 50 | var height = 0; 51 | 52 | $.map(sprites, function (sprite) { 53 | height = sprite.height > height ? sprite.height : height; 54 | width += sprite.width; 55 | }); 56 | 57 | return { 58 | width: width || defaults.width, 59 | height: height || defaults.height 60 | }; 61 | }, 62 | 63 | /** 64 | * ### @placeSprite 65 | * Determine sprite coordinates on the canvas. Once a position is 66 | * determined with no intersections, the sprite is added to the 67 | * placed array. If there is no space, the dimensions are updated. 68 | * Seeks across to place the sprite. 69 | * 70 | * @param {Sprite} sprite The sprite to place 71 | * @param {array} placed An array of sprites already placed 72 | * @param {object} dimensions The current canvas dimensions 73 | */ 74 | placeSprite: function (sprite, placed, dimensions) { 75 | var intersection; 76 | var pass = 0; 77 | var x = 0; 78 | var y = 0; 79 | 80 | while (pass++ < this.settings.maxPass) { 81 | for (x = 0; x <= dimensions.width - sprite.width; x++) { 82 | sprite.x = x; 83 | sprite.y = y; 84 | 85 | intersection = this.intersection(sprite, placed); 86 | 87 | if (!intersection) { 88 | placed.push(sprite); 89 | sprite.show(); 90 | return true; 91 | } 92 | 93 | x = intersection.x + intersection.width - 1; 94 | } 95 | 96 | dimensions.width += sprite.width; 97 | dimensions.height += sprite.height; 98 | } 99 | 100 | return false; 101 | } 102 | }); 103 | 104 | return HorizontalLayout; 105 | 106 | }); 107 | -------------------------------------------------------------------------------- /src/js/layout/compact.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # layout/compact 3 | * 4 | * Constructor for the compact canvas layout manager. Used to determine 5 | * canvas dimensions and to place sprites without intersections (overlap). 6 | * Places sprites in the most compact rectangle possible 7 | * 8 | * > http://draeton.github.io/stitches
9 | * > Copyright 2013 Matthew Cobbs
10 | * > Licensed under the MIT license. 11 | */ 12 | 13 | define([ 14 | "wrap/jquery", 15 | "util/util", 16 | "layout/base" 17 | ], 18 | function ($, util, BaseLayout) { 19 | 20 | "use strict"; 21 | 22 | var defaults = { 23 | maxPass: 2 // number of tries to place sprite 24 | }; 25 | 26 | /** 27 | * ## CompactLayout 28 | * Create a new `CompactLayout` instance 29 | * 30 | * @constructor 31 | * @param {object} options 32 | */ 33 | var CompactLayout = function (options) { 34 | this.settings = $.extend({}, defaults, options); 35 | }; 36 | 37 | util.inherit(CompactLayout, BaseLayout, { 38 | /** 39 | * ### @getDimensions 40 | * Returns an object with the width and height necessary 41 | * to contain the `sprites`. Calculation based on the least area 42 | * needed to contain the sprites. 43 | * 44 | * @param {array} sprites The list of sprites to size for 45 | * @param {object} defaults Default width and height, if no sprites 46 | * @return object 47 | */ 48 | getDimensions: function (sprites, defaults) { 49 | var width = 0; 50 | var height = 0; 51 | var area = 0; 52 | var mean = 0; 53 | 54 | $.map(sprites, function (sprite) { 55 | width = sprite.width > width ? sprite.width : width; 56 | height = sprite.height > height ? sprite.height : height; 57 | area += sprite.area; 58 | }); 59 | 60 | mean = Math.ceil(Math.sqrt(area)); 61 | width = width > mean ? width : mean; 62 | height = height > mean ? height : mean; 63 | 64 | return { 65 | width: width || defaults.width, 66 | height: height || defaults.height 67 | }; 68 | }, 69 | 70 | /** 71 | * ### @placeSprite 72 | * Determine sprite coordinates on the canvas. Once a position is 73 | * determined with no intersections, the sprite is added to the 74 | * placed array. If there is no space, the dimensions are updated. 75 | * Seeks across, then down, to place the sprite. 76 | * 77 | * @param {Sprite} sprite The sprite to place 78 | * @param {array} placed An array of sprites already placed 79 | * @param {object} dimensions The current canvas dimensions 80 | */ 81 | placeSprite: function (sprite, placed, dimensions) { 82 | var intersection; 83 | var pass = 0; 84 | var x = 0; 85 | var y = 0; 86 | 87 | while (pass++ < this.settings.maxPass) { 88 | for (y = 0; y <= (dimensions.height - sprite.height); y++) { 89 | for (x = 0; x <= (dimensions.width - sprite.width); x++) { 90 | sprite.x = x; 91 | sprite.y = y; 92 | 93 | intersection = this.intersection(sprite, placed); 94 | 95 | if (!intersection) { 96 | placed.push(sprite); 97 | sprite.show(); 98 | return true; 99 | } 100 | 101 | x = intersection.x + intersection.width - 1; 102 | } 103 | 104 | y = intersection.y + intersection.height - 1; 105 | } 106 | 107 | dimensions.width += sprite.width; 108 | dimensions.height += sprite.height; 109 | } 110 | } 111 | }); 112 | 113 | return CompactLayout; 114 | 115 | }); 116 | -------------------------------------------------------------------------------- /src/js/module/palette.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # module/palette 3 | * 4 | * Constructor for UI palettes (i.e. dialogs). Inherits from `Toolbar` 5 | * 6 | * > http://draeton.github.io/stitches
7 | * > Copyright 2013 Matthew Cobbs
8 | * > Licensed under the MIT license. 9 | */ 10 | 11 | define([ 12 | "wrap/jquery", 13 | "util/util", 14 | "module/toolbar" 15 | ], 16 | function ($, util, Toolbar) { 17 | 18 | "use strict"; 19 | 20 | var defaults = { 21 | name: "", // helpful for debugging 22 | visible: false, // UI state 23 | actions: {}, // named actions for events; set up with `bind` 24 | fields: {} // input fields; set up with `bind` and `configure` 25 | }; 26 | 27 | /** 28 | * ## Palette 29 | * Create a new `Palette` instance 30 | * 31 | * @constructor 32 | * @param {element} element 33 | * @param {object} options 34 | */ 35 | var Palette = function (element, options) { 36 | this.$element = $(element); 37 | this.settings = $.extend({}, defaults, options); 38 | this.name = this.settings.name; 39 | this.visible = this.settings.visible; 40 | this.actions = this.settings.actions; 41 | this.fields = this.settings.fields; 42 | this.source = null; 43 | 44 | this.init(); 45 | }; 46 | 47 | Palette.classname = ".stitches-palette"; 48 | 49 | util.inherit(Palette, Toolbar, { 50 | /** 51 | * ### @init 52 | * Run methods to prepare the instance for use 53 | */ 54 | init: function () { 55 | this._super("init", this, arguments); 56 | 57 | this.$element.toggleClass("in", this.visible); 58 | }, 59 | 60 | /** 61 | * ### @bind 62 | * Bind event handlers to DOM element. `getHandler` is used to retain 63 | * this instance as the callback execution context. Loops through 64 | * `fields` to bind handlers on matching `name` attributes 65 | */ 66 | bind: function () { 67 | var self = this; 68 | 69 | this._super("bind", this, arguments); 70 | 71 | $.each(this.fields, function (field, events) { 72 | $.each(events, function (event, callback) { 73 | var selector = "[name=" + field + "]"; 74 | var handler = self.getHandler(self, callback); 75 | 76 | self.$element.on(event, selector, handler); 77 | }); 78 | }); 79 | }, 80 | 81 | /** 82 | * ### @open 83 | * Show this palette instance 84 | */ 85 | open: function () { 86 | this.$element.addClass("in"); 87 | this.visible = true; 88 | }, 89 | 90 | /** 91 | * ### @close 92 | * Hide this palette instance 93 | */ 94 | close: function () { 95 | this.$element.removeClass("in"); 96 | this.visible = false; 97 | }, 98 | 99 | /** 100 | * ### @configure 101 | * Configure the values of the inputs 102 | * 103 | * @param {object} properties Defines the data source and input values 104 | */ 105 | configure: function (properties) { 106 | var self = this; 107 | 108 | this.source = properties.source; // reference object for other modules 109 | 110 | $.each(properties.inputs, function (name, value) { 111 | var selector = "[name=" + name + "]"; 112 | var $input = self.$element.find(selector); 113 | var type = $input.attr("type"); 114 | 115 | switch (type) { 116 | case "radio": 117 | case "checkbox": 118 | $input = $input.removeAttr("checked").filter("[value=" + value + "]"); 119 | $input.attr("checked", "checked"); 120 | break; 121 | default: 122 | $input.val(value); 123 | break; 124 | } 125 | }); 126 | } 127 | }); 128 | 129 | return Palette; 130 | 131 | }); -------------------------------------------------------------------------------- /src/js/module/toolbar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # module/toolbar 3 | * 4 | * Constructor for UI toolbars 5 | * 6 | * > http://draeton.github.io/stitches
7 | * > Copyright 2013 Matthew Cobbs
8 | * > Licensed under the MIT license. 9 | */ 10 | 11 | define([ 12 | "wrap/jquery" 13 | ], 14 | function ($) { 15 | 16 | "use strict"; 17 | 18 | var defaults = { 19 | name: "", // helpful for debugging 20 | actions: {} // named actions for events; set up with `bind` 21 | }; 22 | 23 | /** 24 | * ## Toolbar 25 | * Create a new `Toolbar` instance 26 | * 27 | * @constructor 28 | * @param {element} element 29 | * @param {object} options 30 | */ 31 | var Toolbar = function (element, options) { 32 | this.$element = $(element); 33 | this.settings = $.extend({}, defaults, options); 34 | this.name = this.settings.name; 35 | this.actions = this.settings.actions; 36 | 37 | this.init(); 38 | }; 39 | 40 | Toolbar.classname = ".stitches-toolbar"; 41 | 42 | Toolbar.prototype = { 43 | constructor: Toolbar, 44 | 45 | /** 46 | * ### @init 47 | * Run methods to prepare the instance for use 48 | */ 49 | init: function () { 50 | this.bind(); 51 | }, 52 | 53 | /** 54 | * ### @bind 55 | * Bind event handlers to DOM element. `getHandler` is used to retain 56 | * this instance as the callback execution context. Loops through 57 | * `actions` to bind handlers on matching `data-action` attributes 58 | */ 59 | bind: function () { 60 | var self = this; 61 | 62 | $.each(this.actions, function (action, events) { 63 | $.each(events, function (event, callback) { 64 | var selector = "[data-action=" + action + "]"; 65 | var handler = self.getHandler(self, callback); 66 | 67 | if (action === "instance") { 68 | self.$element.on(event, self.getHandler(self, handler)); 69 | } else { 70 | self.$element.on(event, selector, handler); 71 | } 72 | }); 73 | }); 74 | }, 75 | 76 | /** 77 | * ### @getHandler 78 | * Returns an event handler that maintains context and aborts if 79 | * the target is disabled 80 | * 81 | * @param {object} context Execution context 82 | * @param {function} callback Handler callback function 83 | * @return function 84 | */ 85 | getHandler: function (context, callback) { 86 | return function (e) { 87 | var $target = $(e.currentTarget); 88 | 89 | if ($target.is(".disabled")) { 90 | e.stopPropagation(); 91 | e.preventDefault(); 92 | } else { 93 | callback.apply(context, arguments); 94 | } 95 | }; 96 | }, 97 | 98 | /** 99 | * ### @toggleActions 100 | * Enable or disable toolbar actions based on a flag 101 | * 102 | * @param {string} actions Space-delimited string of action names 103 | * @param {boolean} disable If true, disable these actions 104 | */ 105 | toggleActions: function (actions, disable) { 106 | var self = this; 107 | 108 | if (typeof actions === "string") { 109 | actions = actions.split(" "); 110 | } 111 | 112 | $.map(actions, function (action) { 113 | var $tool = self.$element.find("[data-action=" + action + "]"); 114 | 115 | $tool.toggleClass("disabled", disable); 116 | }); 117 | }, 118 | 119 | /** 120 | * ### @enable 121 | * Short-hand for `toggleActions` to enable 122 | * 123 | * @param {string} actions Space-delimited string of action names 124 | */ 125 | enable: function (actions) { 126 | this.toggleActions(actions, false); 127 | }, 128 | 129 | /** 130 | * ### @disable 131 | * Short-hand for `toggleActions` to disable 132 | * 133 | * @param {string} actions Space-delimited string of action names 134 | */ 135 | disable: function (actions) { 136 | this.toggleActions(actions, true); 137 | } 138 | }; 139 | 140 | return Toolbar; 141 | 142 | }); -------------------------------------------------------------------------------- /src/js/manager/layout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * # manager/layout 3 | * 4 | * Methods for setting the canvas layout and stitching the sprites together 5 | * (i.e. placing them on the canvas) 6 | * 7 | * > http://draeton.github.io/stitches
8 | * > Copyright 2013 Matthew Cobbs
9 | * > Licensed under the MIT license. 10 | */ 11 | 12 | define([ 13 | "wrap/jquery", 14 | "layout/compact", 15 | "layout/vertical", 16 | "layout/horizontal" 17 | ], 18 | function ($, CompactLayout, VerticalLayout, HorizontalLayout) { 19 | 20 | "use strict"; 21 | 22 | // **Canvas layout managers** 23 | var managers = { 24 | compact: CompactLayout, 25 | vertical: VerticalLayout, 26 | horizontal: HorizontalLayout 27 | }; 28 | 29 | // **Module definition** 30 | return { 31 | /** 32 | * ### @set 33 | * Set the working layout manager instance by type 34 | * 35 | * @param {string} type The layout manager type 36 | */ 37 | set: function (type) { 38 | var Manager = managers[type] || managers.compact; 39 | 40 | this.manager = new Manager(); 41 | }, 42 | 43 | /** 44 | * ### @getDimensions 45 | * Get the dimensions necessary to place the sprites 46 | * 47 | * @param {array} sprites A list of sprites to place 48 | * @param {object} defaults Default dimensions if no sprites 49 | * @return object 50 | */ 51 | getDimensions: function (sprites, defaults) { 52 | return this.manager.getDimensions(sprites, defaults); 53 | }, 54 | 55 | /** 56 | * ### @placeSprites 57 | * Position a list of sprites to fit in dimensions and layout 58 | * 59 | * @param {array} sprites To place 60 | * @param {array} placed Already placed 61 | * @param {object} dimensions Working width and height 62 | * @param {function} progress Function to update display on progress 63 | */ 64 | placeSprites: function (sprites, placed, dimensions, progress) { 65 | var self = this; 66 | 67 | progress(0, "info"); 68 | 69 | $.map(sprites, function (sprite) { 70 | if (!sprite.placed) { 71 | sprite.placed = self.manager.placeSprite(sprite, placed, dimensions); 72 | } 73 | 74 | progress(placed.length / sprites.length); 75 | }); 76 | 77 | sprites = $.map(sprites, function (sprite) { 78 | return sprite.placed ? null : sprite; 79 | }); 80 | }, 81 | 82 | /** 83 | * ### @trim 84 | * Trim dimensions to only contain placed sprites 85 | * 86 | * @param {array} sprites A list of sprites 87 | * @param {object} dimensions Working width and height 88 | */ 89 | trim: function (sprites, dimensions) { 90 | var w = 0; 91 | var h = 0; 92 | 93 | $.map(sprites, function (sprite) { 94 | w = w > sprite.x + sprite.width ? w : sprite.x + sprite.width; 95 | h = h > sprite.y + sprite.height ? h : sprite.y + sprite.height; 96 | }); 97 | 98 | dimensions.width = w || dimensions.width; 99 | dimensions.height = h || dimensions.height; 100 | }, 101 | 102 | /** 103 | * ### @getSpritesheet 104 | * Returns an image using the browser canvas element's drawing context. 105 | * Triggers a non-fatal error if anything fails 106 | * 107 | * @param {array} options.sprites A list of sprites 108 | * @param{object} options.dimensions Working width and height 109 | * @return string 110 | */ 111 | getSpritesheet: function (options) { 112 | var sprites = options.sprites; 113 | var dimensions = options.dimensions; 114 | var canvas; 115 | var context; 116 | var spritesheet; 117 | 118 | canvas = document.createElement("canvas"); 119 | canvas.width = dimensions.width; 120 | canvas.height = dimensions.height; 121 | 122 | try { 123 | context = canvas.getContext("2d"); 124 | 125 | $.map(sprites, function (sprite) { 126 | var x = sprite.left(); 127 | var y = sprite.top(); 128 | 129 | context.drawImage(sprite.image, x, y); 130 | }); 131 | 132 | spritesheet = canvas.toDataURL("image/png"); 133 | } catch (e) { 134 | this.$element.trigger("error", [e]); 135 | } 136 | 137 | return spritesheet; 138 | } 139 | }; 140 | 141 | }); -------------------------------------------------------------------------------- /libs/qunit/qunit.css: -------------------------------------------------------------------------------- 1 | /** 2 | * QUnit v1.11.0 - A JavaScript Unit Testing Framework 3 | * 4 | * http://qunitjs.com 5 | * 6 | * Copyright 2012 jQuery Foundation and other contributors 7 | * Released under the MIT license. 8 | * http://jquery.org/license 9 | */ 10 | 11 | /** Font Family and Sizes */ 12 | 13 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { 14 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; 15 | } 16 | 17 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } 18 | #qunit-tests { font-size: smaller; } 19 | 20 | 21 | /** Resets */ 22 | 23 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter { 24 | margin: 0; 25 | padding: 0; 26 | } 27 | 28 | 29 | /** Header */ 30 | 31 | #qunit-header { 32 | padding: 0.5em 0 0.5em 1em; 33 | 34 | color: #8699a4; 35 | background-color: #0d3349; 36 | 37 | font-size: 1.5em; 38 | line-height: 1em; 39 | font-weight: normal; 40 | 41 | border-radius: 5px 5px 0 0; 42 | -moz-border-radius: 5px 5px 0 0; 43 | -webkit-border-top-right-radius: 5px; 44 | -webkit-border-top-left-radius: 5px; 45 | } 46 | 47 | #qunit-header a { 48 | text-decoration: none; 49 | color: #c2ccd1; 50 | } 51 | 52 | #qunit-header a:hover, 53 | #qunit-header a:focus { 54 | color: #fff; 55 | } 56 | 57 | #qunit-testrunner-toolbar label { 58 | display: inline-block; 59 | padding: 0 .5em 0 .1em; 60 | } 61 | 62 | #qunit-banner { 63 | height: 5px; 64 | } 65 | 66 | #qunit-testrunner-toolbar { 67 | padding: 0.5em 0 0.5em 2em; 68 | color: #5E740B; 69 | background-color: #eee; 70 | overflow: hidden; 71 | } 72 | 73 | #qunit-userAgent { 74 | padding: 0.5em 0 0.5em 2.5em; 75 | background-color: #2b81af; 76 | color: #fff; 77 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 78 | } 79 | 80 | #qunit-modulefilter-container { 81 | float: right; 82 | } 83 | 84 | /** Tests: Pass/Fail */ 85 | 86 | #qunit-tests { 87 | list-style-position: inside; 88 | } 89 | 90 | #qunit-tests li { 91 | padding: 0.4em 0.5em 0.4em 2.5em; 92 | border-bottom: 1px solid #fff; 93 | list-style-position: inside; 94 | } 95 | 96 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { 97 | display: none; 98 | } 99 | 100 | #qunit-tests li strong { 101 | cursor: pointer; 102 | } 103 | 104 | #qunit-tests li a { 105 | padding: 0.5em; 106 | color: #c2ccd1; 107 | text-decoration: none; 108 | } 109 | #qunit-tests li a:hover, 110 | #qunit-tests li a:focus { 111 | color: #000; 112 | } 113 | 114 | #qunit-tests li .runtime { 115 | float: right; 116 | font-size: smaller; 117 | } 118 | 119 | .qunit-assert-list { 120 | margin-top: 0.5em; 121 | padding: 0.5em; 122 | 123 | background-color: #fff; 124 | 125 | border-radius: 5px; 126 | -moz-border-radius: 5px; 127 | -webkit-border-radius: 5px; 128 | } 129 | 130 | .qunit-collapsed { 131 | display: none; 132 | } 133 | 134 | #qunit-tests table { 135 | border-collapse: collapse; 136 | margin-top: .2em; 137 | } 138 | 139 | #qunit-tests th { 140 | text-align: right; 141 | vertical-align: top; 142 | padding: 0 .5em 0 0; 143 | } 144 | 145 | #qunit-tests td { 146 | vertical-align: top; 147 | } 148 | 149 | #qunit-tests pre { 150 | margin: 0; 151 | white-space: pre-wrap; 152 | word-wrap: break-word; 153 | } 154 | 155 | #qunit-tests del { 156 | background-color: #e0f2be; 157 | color: #374e0c; 158 | text-decoration: none; 159 | } 160 | 161 | #qunit-tests ins { 162 | background-color: #ffcaca; 163 | color: #500; 164 | text-decoration: none; 165 | } 166 | 167 | /*** Test Counts */ 168 | 169 | #qunit-tests b.counts { color: black; } 170 | #qunit-tests b.passed { color: #5E740B; } 171 | #qunit-tests b.failed { color: #710909; } 172 | 173 | #qunit-tests li li { 174 | padding: 5px; 175 | background-color: #fff; 176 | border-bottom: none; 177 | list-style-position: inside; 178 | } 179 | 180 | /*** Passing Styles */ 181 | 182 | #qunit-tests li li.pass { 183 | color: #3c510c; 184 | background-color: #fff; 185 | border-left: 10px solid #C6E746; 186 | } 187 | 188 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } 189 | #qunit-tests .pass .test-name { color: #366097; } 190 | 191 | #qunit-tests .pass .test-actual, 192 | #qunit-tests .pass .test-expected { color: #999999; } 193 | 194 | #qunit-banner.qunit-pass { background-color: #C6E746; } 195 | 196 | /*** Failing Styles */ 197 | 198 | #qunit-tests li li.fail { 199 | color: #710909; 200 | background-color: #fff; 201 | border-left: 10px solid #EE5757; 202 | white-space: pre; 203 | } 204 | 205 | #qunit-tests > li:last-child { 206 | border-radius: 0 0 5px 5px; 207 | -moz-border-radius: 0 0 5px 5px; 208 | -webkit-border-bottom-right-radius: 5px; 209 | -webkit-border-bottom-left-radius: 5px; 210 | } 211 | 212 | #qunit-tests .fail { color: #000000; background-color: #EE5757; } 213 | #qunit-tests .fail .test-name, 214 | #qunit-tests .fail .module-name { color: #000000; } 215 | 216 | #qunit-tests .fail .test-actual { color: #EE5757; } 217 | #qunit-tests .fail .test-expected { color: green; } 218 | 219 | #qunit-banner.qunit-fail { background-color: #EE5757; } 220 | 221 | 222 | /** Result */ 223 | 224 | #qunit-testresult { 225 | padding: 0.5em 0.5em 0.5em 2.5em; 226 | 227 | color: #2b81af; 228 | background-color: #D2E0E6; 229 | 230 | border-bottom: 1px solid white; 231 | } 232 | #qunit-testresult .module-name { 233 | font-weight: bold; 234 | } 235 | 236 | /** Fixture */ 237 | 238 | #qunit-fixture { 239 | position: absolute; 240 | top: -10000px; 241 | left: -10000px; 242 | width: 1000px; 243 | height: 1000px; 244 | } -------------------------------------------------------------------------------- /libs/store/store.js: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2010-2012 Marcus Westin */;(function(){ 2 | var store = {}, 3 | win = window, 4 | doc = win.document, 5 | localStorageName = 'localStorage', 6 | namespace = '__storejs__', 7 | storage 8 | 9 | store.disabled = false 10 | store.set = function(key, value) {} 11 | store.get = function(key) {} 12 | store.remove = function(key) {} 13 | store.clear = function() {} 14 | store.transact = function(key, defaultVal, transactionFn) { 15 | var val = store.get(key) 16 | if (transactionFn == null) { 17 | transactionFn = defaultVal 18 | defaultVal = null 19 | } 20 | if (typeof val == 'undefined') { val = defaultVal || {} } 21 | transactionFn(val) 22 | store.set(key, val) 23 | } 24 | store.setAll = function() {} 25 | store.getAll = function() {} 26 | 27 | store.serialize = function(value) { 28 | return JSON.stringify(value) 29 | } 30 | store.deserialize = function(value) { 31 | if (typeof value != 'string') { return undefined } 32 | try { return JSON.parse(value) } 33 | catch(e) { return value || undefined } 34 | } 35 | 36 | // Functions to encapsulate questionable FireFox 3.6.13 behavior 37 | // when about.config::dom.storage.enabled === false 38 | // See https://github.com/marcuswestin/store.js/issues#issue/13 39 | function isLocalStorageNameSupported() { 40 | try { return (localStorageName in win && win[localStorageName]) } 41 | catch(err) { return false } 42 | } 43 | 44 | if (isLocalStorageNameSupported()) { 45 | storage = win[localStorageName] 46 | store.set = function(key, val) { 47 | if (typeof key == "object") { return store.setAll(key) } 48 | if (val === undefined) { return store.remove(key) } 49 | storage.setItem(key, store.serialize(val)) 50 | return val 51 | } 52 | store.get = function(key) { 53 | if (key === undefined) { return store.getAll() } 54 | return store.deserialize(storage.getItem(key)) 55 | } 56 | store.remove = function(key) { storage.removeItem(key) } 57 | store.clear = function() { storage.clear() } 58 | store.setAll = function (vals) { 59 | for (var i in vals) { 60 | vals[i] = store.set(i, vals[i]) 61 | } 62 | } 63 | store.getAll = function() { 64 | var ret = {} 65 | for (var i=0; idocument.w=window