rails_pitfall 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. data/.gitignore +18 -0
  2. data/.rvmrc +48 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +1 -0
  5. data/README.md +45 -0
  6. data/Rakefile +1 -0
  7. data/lib/rails_pitfall.rb +18 -0
  8. data/lib/rails_pitfall/version.rb +3 -0
  9. data/rails_pitfall.gemspec +25 -0
  10. data/vendor/assets/images/backgrounds/wild_oliva.png +0 -0
  11. data/vendor/assets/images/backgrounds/wild_oliva_@2X.png +0 -0
  12. data/vendor/assets/images/backgrounds/wild_oliva_blue_dark.png +0 -0
  13. data/vendor/assets/images/backgrounds/wild_oliva_blue_light.png +0 -0
  14. data/vendor/assets/images/backgrounds/wild_oliva_dark.png +0 -0
  15. data/vendor/assets/images/backgrounds/wild_oliva_light.png +0 -0
  16. data/vendor/assets/images/backgrounds/wild_oliva_light_head.png +0 -0
  17. data/vendor/assets/images/ui.totop.png +0 -0
  18. data/vendor/assets/javascript/easing.js +141 -0
  19. data/vendor/assets/javascript/isotope/jquery.isotope.js +1407 -0
  20. data/vendor/assets/javascript/jquery.ui/jquery.ui.totop.js +55 -0
  21. data/vendor/assets/javascript/rails_strap.js +9 -0
  22. data/vendor/assets/javascript/rails_strap_modernizer.js +4 -0
  23. data/vendor/assets/javascript/restart_theme.js +213 -0
  24. data/vendor/assets/stylesheets/animate/animate.css +3263 -0
  25. data/vendor/assets/stylesheets/bootstrap_customization.less +2 -0
  26. data/vendor/assets/stylesheets/custom_variables.less +301 -0
  27. data/vendor/assets/stylesheets/flexslider_customization.css +20 -0
  28. data/vendor/assets/stylesheets/font-awesome-ie7.min.css +22 -0
  29. data/vendor/assets/stylesheets/fontawesome_customization.less +6 -0
  30. data/vendor/assets/stylesheets/isotope/css/style.css +77 -0
  31. data/vendor/assets/stylesheets/rails_strap.css.scss +11 -0
  32. data/vendor/assets/stylesheets/style.less +1726 -0
  33. metadata +190 -0
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .git
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.rvmrc ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # This is an RVM Project .rvmrc file, used to automatically load the ruby
4
+ # development environment upon cd'ing into the directory
5
+
6
+ # First we specify our desired <ruby>[@<gemset>], the @gemset name is optional,
7
+ # Only full ruby name is supported here, for short names use:
8
+ # echo "rvm use 1.9.3" > .rvmrc
9
+ environment_id="ruby-1.9.3@rails_pitfall"
10
+
11
+ # Uncomment the following lines if you want to verify rvm version per project
12
+ # rvmrc_rvm_version="1.18.21 (stable)" # 1.10.1 seams as a safe start
13
+ # eval "$(echo ${rvm_version}.${rvmrc_rvm_version} | awk -F. '{print "[[ "$1*65536+$2*256+$3" -ge "$4*65536+$5*256+$6" ]]"}' )" || {
14
+ # echo "This .rvmrc file requires at least RVM ${rvmrc_rvm_version}, aborting loading."
15
+ # return 1
16
+ # }
17
+
18
+ # First we attempt to load the desired environment directly from the environment
19
+ # file. This is very fast and efficient compared to running through the entire
20
+ # CLI and selector. If you want feedback on which environment was used then
21
+ # insert the word 'use' after --create as this triggers verbose mode.
22
+ if [[ -d "${rvm_path:-$HOME/.rvm}/environments"
23
+ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
24
+ then
25
+ \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
26
+ [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] &&
27
+ \. "${rvm_path:-$HOME/.rvm}/hooks/after_use" || true
28
+ else
29
+ # If the environment file has not yet been created, use the RVM CLI to select.
30
+ rvm --create "$environment_id" || {
31
+ echo "Failed to create RVM environment '${environment_id}'."
32
+ return 1
33
+ }
34
+ fi
35
+
36
+ # If you use bundler, this might be useful to you:
37
+ # if [[ -s Gemfile ]] && {
38
+ # ! builtin command -v bundle >/dev/null ||
39
+ # builtin command -v bundle | GREP_OPTIONS= \grep $rvm_path/bin/bundle >/dev/null
40
+ # }
41
+ # then
42
+ # printf "%b" "The rubygem 'bundler' is not installed. Installing it now.\n"
43
+ # gem install bundler
44
+ # fi
45
+ # if [[ -s Gemfile ]] && builtin command -v bundle >/dev/null
46
+ # then
47
+ # bundle install | GREP_OPTIONS= \grep -vE '^Using|Your bundle is complete'
48
+ # fi
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rails_pitfall.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1 @@
1
+ Copyright (c) 2013 by leonart.gr & wintersolutions.de
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # RailsPitfall
2
+
3
+ Multipurpose HTML Template based on twitter bootstrap.
4
+
5
+ ## Installation
6
+
7
+ Install the Gem yourself by executing:
8
+
9
+ $ gem install rails_pitfall
10
+
11
+ in the directory you downloaded the Gem.
12
+
13
+
14
+ Add this line to your application's Gemfile:
15
+
16
+ gem 'rails_pitfall'
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Then add this to app/assets/javascripts/application.js
23
+
24
+ //= require rails_pitfall
25
+
26
+ And this to app/assets/stylesheets/application.css
27
+
28
+ *= require rails_pitfall
29
+
30
+ ## Features
31
+ * Clean, Responsive Design
32
+ * Good typography and large photography
33
+ * Built with {less}
34
+ * Subtle animations & a fresh collapsing header effect
35
+
36
+
37
+ * jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license
38
+ * Bootstrap v3.0
39
+ * Font Awesome 3.0.2
40
+ * Modernizr 2.6.2 (Custom Build)
41
+ * Animate.css * http://daneden.me/animate
42
+ * Isotope v1.5.25 jQuery plugin http://isotope.metafizzy.co (Commercial Licence)
43
+ * UItoTop jQuery Plugin 1.2 by Matt Varone
44
+ * Background pattern by Subtle Patterns (http://subtlepatterns.com/)
45
+ * Google OpenSans Webfont
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,18 @@
1
+ require "rails_pitfall/version"
2
+
3
+ module RailsPitfall
4
+ class Engine < ::Rails::Engine
5
+ # see http://stackoverflow.com/questions/12256291/dependency-included-in-gemspec-not-added-to-asset-pipeline-in-rails-engine
6
+ require "twitter-bootstrap-rails"
7
+ require "flexslider"
8
+ require "prettyphoto-rails"
9
+ require "jquery-rails"
10
+ require "less-rails"
11
+
12
+ if Rails.version >= '3.1'
13
+ initializer :assets do |config|
14
+ Rails.application.config.assets.precompile += %w( font-awesome-ie7.min.css rails_pitfall_modernizer.js )
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module RailsPitfall
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rails_pitfall/version'
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "rails_pitfall"
7
+ spec.version = RailsPitfall::VERSION
8
+ spec.authors = ["Oscar Quiroz"]
9
+ spec.email = ["oscaryunue@gmail.com"]
10
+ spec.description = %q{bundle of components, for a core application.}
11
+ spec.summary = %q{install and configure all you need for a multipurpose applications.}
12
+ spec.homepage = ""
13
+ spec.license = "MIT"
14
+ spec.files = `git ls-files`.split($/)
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+ spec.add_dependency "twitter-bootstrap-rails", " ~> 2.2"
19
+ spec.add_dependency "flexslider", "2.0.2"
20
+ spec.add_dependency "prettyphoto-rails", "0.2.0"
21
+ spec.add_dependency "jquery-rails", "~> 2.0"
22
+ spec.add_dependency "less-rails", "~> 2.2"
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ end
Binary file
@@ -0,0 +1,141 @@
1
+ /*
2
+ * jQuery EasIng v1.1.2 - http://gsgd.co.uk/sandbox/jquery.easIng.php
3
+ *
4
+ * Uses the built In easIng capabilities added In jQuery 1.1
5
+ * to offer multiple easIng options
6
+ *
7
+ * Copyright (c) 2007 George Smith
8
+ * Licensed under the MIT License:
9
+ * http://www.opensource.org/licenses/mit-license.php
10
+ */
11
+
12
+ // t: current time, b: begInnIng value, c: change In value, d: duration
13
+
14
+ jQuery.extend( jQuery.easing,
15
+ {
16
+ easeInQuad: function (x, t, b, c, d) {
17
+ return c*(t/=d)*t + b;
18
+ },
19
+ easeOutQuad: function (x, t, b, c, d) {
20
+ return -c *(t/=d)*(t-2) + b;
21
+ },
22
+ easeInOutQuad: function (x, t, b, c, d) {
23
+ if ((t/=d/2) < 1) return c/2*t*t + b;
24
+ return -c/2 * ((--t)*(t-2) - 1) + b;
25
+ },
26
+ easeInCubic: function (x, t, b, c, d) {
27
+ return c*(t/=d)*t*t + b;
28
+ },
29
+ easeOutCubic: function (x, t, b, c, d) {
30
+ return c*((t=t/d-1)*t*t + 1) + b;
31
+ },
32
+ easeInOutCubic: function (x, t, b, c, d) {
33
+ if ((t/=d/2) < 1) return c/2*t*t*t + b;
34
+ return c/2*((t-=2)*t*t + 2) + b;
35
+ },
36
+ easeInQuart: function (x, t, b, c, d) {
37
+ return c*(t/=d)*t*t*t + b;
38
+ },
39
+ easeOutQuart: function (x, t, b, c, d) {
40
+ return -c * ((t=t/d-1)*t*t*t - 1) + b;
41
+ },
42
+ easeInOutQuart: function (x, t, b, c, d) {
43
+ if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
44
+ return -c/2 * ((t-=2)*t*t*t - 2) + b;
45
+ },
46
+ easeInQuint: function (x, t, b, c, d) {
47
+ return c*(t/=d)*t*t*t*t + b;
48
+ },
49
+ easeOutQuint: function (x, t, b, c, d) {
50
+ return c*((t=t/d-1)*t*t*t*t + 1) + b;
51
+ },
52
+ easeInOutQuint: function (x, t, b, c, d) {
53
+ if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
54
+ return c/2*((t-=2)*t*t*t*t + 2) + b;
55
+ },
56
+ easeInSine: function (x, t, b, c, d) {
57
+ return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
58
+ },
59
+ easeOutSine: function (x, t, b, c, d) {
60
+ return c * Math.sin(t/d * (Math.PI/2)) + b;
61
+ },
62
+ easeInOutSine: function (x, t, b, c, d) {
63
+ return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
64
+ },
65
+ easeInExpo: function (x, t, b, c, d) {
66
+ return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
67
+ },
68
+ easeOutExpo: function (x, t, b, c, d) {
69
+ return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
70
+ },
71
+ easeInOutExpo: function (x, t, b, c, d) {
72
+ if (t==0) return b;
73
+ if (t==d) return b+c;
74
+ if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
75
+ return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
76
+ },
77
+ easeInCirc: function (x, t, b, c, d) {
78
+ return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
79
+ },
80
+ easeOutCirc: function (x, t, b, c, d) {
81
+ return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
82
+ },
83
+ easeInOutCirc: function (x, t, b, c, d) {
84
+ if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
85
+ return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
86
+ },
87
+ easeInElastic: function (x, t, b, c, d) {
88
+ var s=1.70158;var p=0;var a=c;
89
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
90
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
91
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
92
+ return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
93
+ },
94
+ easeOutElastic: function (x, t, b, c, d) {
95
+ var s=1.70158;var p=0;var a=c;
96
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
97
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
98
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
99
+ return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
100
+ },
101
+ easeInOutElastic: function (x, t, b, c, d) {
102
+ var s=1.70158;var p=0;var a=c;
103
+ if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
104
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
105
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
106
+ if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
107
+ return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
108
+ },
109
+ easeInBack: function (x, t, b, c, d, s) {
110
+ if (s == undefined) s = 1.70158;
111
+ return c*(t/=d)*t*((s+1)*t - s) + b;
112
+ },
113
+ easeOutBack: function (x, t, b, c, d, s) {
114
+ if (s == undefined) s = 1.70158;
115
+ return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
116
+ },
117
+ easeInOutBack: function (x, t, b, c, d, s) {
118
+ if (s == undefined) s = 1.70158;
119
+ if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
120
+ return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
121
+ },
122
+ easeInBounce: function (x, t, b, c, d) {
123
+ return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
124
+ },
125
+ easeOutBounce: function (x, t, b, c, d) {
126
+ if ((t/=d) < (1/2.75)) {
127
+ return c*(7.5625*t*t) + b;
128
+ } else if (t < (2/2.75)) {
129
+ return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
130
+ } else if (t < (2.5/2.75)) {
131
+ return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
132
+ } else {
133
+ return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
134
+ }
135
+ },
136
+ easeInOutBounce: function (x, t, b, c, d) {
137
+ if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
138
+ return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
139
+ }
140
+ });
141
+
@@ -0,0 +1,1407 @@
1
+ /**
2
+ * Isotope v1.5.25
3
+ * An exquisite jQuery plugin for magical layouts
4
+ * http://isotope.metafizzy.co
5
+ *
6
+ * Commercial use requires one-time license fee
7
+ * http://metafizzy.co/#licenses
8
+ *
9
+ * Copyright 2012 David DeSandro / Metafizzy
10
+ */
11
+
12
+ /*jshint asi: true, browser: true, curly: true, eqeqeq: true, forin: false, immed: false, newcap: true, noempty: true, strict: true, undef: true */
13
+ /*global jQuery: false */
14
+
15
+ (function( window, $, undefined ){
16
+
17
+ 'use strict';
18
+
19
+ // get global vars
20
+ var document = window.document;
21
+ var Modernizr = window.Modernizr;
22
+
23
+ // helper function
24
+ var capitalize = function( str ) {
25
+ return str.charAt(0).toUpperCase() + str.slice(1);
26
+ };
27
+
28
+ // ========================= getStyleProperty by kangax ===============================
29
+ // http://perfectionkills.com/feature-testing-css-properties/
30
+
31
+ var prefixes = 'Moz Webkit O Ms'.split(' ');
32
+
33
+ var getStyleProperty = function( propName ) {
34
+ var style = document.documentElement.style,
35
+ prefixed;
36
+
37
+ // test standard property first
38
+ if ( typeof style[propName] === 'string' ) {
39
+ return propName;
40
+ }
41
+
42
+ // capitalize
43
+ propName = capitalize( propName );
44
+
45
+ // test vendor specific properties
46
+ for ( var i=0, len = prefixes.length; i < len; i++ ) {
47
+ prefixed = prefixes[i] + propName;
48
+ if ( typeof style[ prefixed ] === 'string' ) {
49
+ return prefixed;
50
+ }
51
+ }
52
+ };
53
+
54
+ var transformProp = getStyleProperty('transform'),
55
+ transitionProp = getStyleProperty('transitionProperty');
56
+
57
+
58
+ // ========================= miniModernizr ===============================
59
+ // <3<3<3 and thanks to Faruk and Paul for doing the heavy lifting
60
+
61
+ /*!
62
+ * Modernizr v1.6ish: miniModernizr for Isotope
63
+ * http://www.modernizr.com
64
+ *
65
+ * Developed by:
66
+ * - Faruk Ates http://farukat.es/
67
+ * - Paul Irish http://paulirish.com/
68
+ *
69
+ * Copyright (c) 2009-2010
70
+ * Dual-licensed under the BSD or MIT licenses.
71
+ * http://www.modernizr.com/license/
72
+ */
73
+
74
+ /*
75
+ * This version whittles down the script just to check support for
76
+ * CSS transitions, transforms, and 3D transforms.
77
+ */
78
+
79
+ var tests = {
80
+ csstransforms: function() {
81
+ return !!transformProp;
82
+ },
83
+
84
+ csstransforms3d: function() {
85
+ var test = !!getStyleProperty('perspective');
86
+ // double check for Chrome's false positive
87
+ if ( test ) {
88
+ var vendorCSSPrefixes = ' -o- -moz- -ms- -webkit- -khtml- '.split(' '),
89
+ mediaQuery = '@media (' + vendorCSSPrefixes.join('transform-3d),(') + 'modernizr)',
90
+ $style = $('<style>' + mediaQuery + '{#modernizr{height:3px}}' + '</style>')
91
+ .appendTo('head'),
92
+ $div = $('<div id="modernizr" />').appendTo('html');
93
+
94
+ test = $div.height() === 3;
95
+
96
+ $div.remove();
97
+ $style.remove();
98
+ }
99
+ return test;
100
+ },
101
+
102
+ csstransitions: function() {
103
+ return !!transitionProp;
104
+ }
105
+ };
106
+
107
+ var testName;
108
+
109
+ if ( Modernizr ) {
110
+ // if there's a previous Modernzir, check if there are necessary tests
111
+ for ( testName in tests) {
112
+ if ( !Modernizr.hasOwnProperty( testName ) ) {
113
+ // if test hasn't been run, use addTest to run it
114
+ Modernizr.addTest( testName, tests[ testName ] );
115
+ }
116
+ }
117
+ } else {
118
+ // or create new mini Modernizr that just has the 3 tests
119
+ Modernizr = window.Modernizr = {
120
+ _version : '1.6ish: miniModernizr for Isotope'
121
+ };
122
+
123
+ var classes = ' ';
124
+ var result;
125
+
126
+ // Run through tests
127
+ for ( testName in tests) {
128
+ result = tests[ testName ]();
129
+ Modernizr[ testName ] = result;
130
+ classes += ' ' + ( result ? '' : 'no-' ) + testName;
131
+ }
132
+
133
+ // Add the new classes to the <html> element.
134
+ $('html').addClass( classes );
135
+ }
136
+
137
+
138
+ // ========================= isoTransform ===============================
139
+
140
+ /**
141
+ * provides hooks for .css({ scale: value, translate: [x, y] })
142
+ * Progressively enhanced CSS transforms
143
+ * Uses hardware accelerated 3D transforms for Safari
144
+ * or falls back to 2D transforms.
145
+ */
146
+
147
+ if ( Modernizr.csstransforms ) {
148
+
149
+ // i.e. transformFnNotations.scale(0.5) >> 'scale3d( 0.5, 0.5, 1)'
150
+ var transformFnNotations = Modernizr.csstransforms3d ?
151
+ { // 3D transform functions
152
+ translate : function ( position ) {
153
+ return 'translate3d(' + position[0] + 'px, ' + position[1] + 'px, 0) ';
154
+ },
155
+ scale : function ( scale ) {
156
+ return 'scale3d(' + scale + ', ' + scale + ', 1) ';
157
+ }
158
+ } :
159
+ { // 2D transform functions
160
+ translate : function ( position ) {
161
+ return 'translate(' + position[0] + 'px, ' + position[1] + 'px) ';
162
+ },
163
+ scale : function ( scale ) {
164
+ return 'scale(' + scale + ') ';
165
+ }
166
+ }
167
+ ;
168
+
169
+ var setIsoTransform = function ( elem, name, value ) {
170
+ // unpack current transform data
171
+ var data = $.data( elem, 'isoTransform' ) || {},
172
+ newData = {},
173
+ fnName,
174
+ transformObj = {},
175
+ transformValue;
176
+
177
+ // i.e. newData.scale = 0.5
178
+ newData[ name ] = value;
179
+ // extend new value over current data
180
+ $.extend( data, newData );
181
+
182
+ for ( fnName in data ) {
183
+ transformValue = data[ fnName ];
184
+ transformObj[ fnName ] = transformFnNotations[ fnName ]( transformValue );
185
+ }
186
+
187
+ // get proper order
188
+ // ideally, we could loop through this give an array, but since we only have
189
+ // a couple transforms we're keeping track of, we'll do it like so
190
+ var translateFn = transformObj.translate || '',
191
+ scaleFn = transformObj.scale || '',
192
+ // sorting so translate always comes first
193
+ valueFns = translateFn + scaleFn;
194
+
195
+ // set data back in elem
196
+ $.data( elem, 'isoTransform', data );
197
+
198
+ // set name to vendor specific property
199
+ elem.style[ transformProp ] = valueFns;
200
+ };
201
+
202
+ // ==================== scale ===================
203
+
204
+ $.cssNumber.scale = true;
205
+
206
+ $.cssHooks.scale = {
207
+ set: function( elem, value ) {
208
+ // uncomment this bit if you want to properly parse strings
209
+ // if ( typeof value === 'string' ) {
210
+ // value = parseFloat( value );
211
+ // }
212
+ setIsoTransform( elem, 'scale', value );
213
+ },
214
+ get: function( elem, computed ) {
215
+ var transform = $.data( elem, 'isoTransform' );
216
+ return transform && transform.scale ? transform.scale : 1;
217
+ }
218
+ };
219
+
220
+ $.fx.step.scale = function( fx ) {
221
+ $.cssHooks.scale.set( fx.elem, fx.now+fx.unit );
222
+ };
223
+
224
+
225
+ // ==================== translate ===================
226
+
227
+ $.cssNumber.translate = true;
228
+
229
+ $.cssHooks.translate = {
230
+ set: function( elem, value ) {
231
+
232
+ // uncomment this bit if you want to properly parse strings
233
+ // if ( typeof value === 'string' ) {
234
+ // value = value.split(' ');
235
+ // }
236
+ //
237
+ // var i, val;
238
+ // for ( i = 0; i < 2; i++ ) {
239
+ // val = value[i];
240
+ // if ( typeof val === 'string' ) {
241
+ // val = parseInt( val );
242
+ // }
243
+ // }
244
+
245
+ setIsoTransform( elem, 'translate', value );
246
+ },
247
+
248
+ get: function( elem, computed ) {
249
+ var transform = $.data( elem, 'isoTransform' );
250
+ return transform && transform.translate ? transform.translate : [ 0, 0 ];
251
+ }
252
+ };
253
+
254
+ }
255
+
256
+ // ========================= get transition-end event ===============================
257
+ var transitionEndEvent, transitionDurProp;
258
+
259
+ if ( Modernizr.csstransitions ) {
260
+ transitionEndEvent = {
261
+ WebkitTransitionProperty: 'webkitTransitionEnd', // webkit
262
+ MozTransitionProperty: 'transitionend',
263
+ OTransitionProperty: 'oTransitionEnd otransitionend',
264
+ transitionProperty: 'transitionend'
265
+ }[ transitionProp ];
266
+
267
+ transitionDurProp = getStyleProperty('transitionDuration');
268
+ }
269
+
270
+ // ========================= smartresize ===============================
271
+
272
+ /*
273
+ * smartresize: debounced resize event for jQuery
274
+ *
275
+ * latest version and complete README available on Github:
276
+ * https://github.com/louisremi/jquery.smartresize.js
277
+ *
278
+ * Copyright 2011 @louis_remi
279
+ * Licensed under the MIT license.
280
+ */
281
+
282
+ var $event = $.event,
283
+ dispatchMethod = $.event.handle ? 'handle' : 'dispatch',
284
+ resizeTimeout;
285
+
286
+ $event.special.smartresize = {
287
+ setup: function() {
288
+ $(this).bind( "resize", $event.special.smartresize.handler );
289
+ },
290
+ teardown: function() {
291
+ $(this).unbind( "resize", $event.special.smartresize.handler );
292
+ },
293
+ handler: function( event, execAsap ) {
294
+ // Save the context
295
+ var context = this,
296
+ args = arguments;
297
+
298
+ // set correct event type
299
+ event.type = "smartresize";
300
+
301
+ if ( resizeTimeout ) { clearTimeout( resizeTimeout ); }
302
+ resizeTimeout = setTimeout(function() {
303
+ $event[ dispatchMethod ].apply( context, args );
304
+ }, execAsap === "execAsap"? 0 : 100 );
305
+ }
306
+ };
307
+
308
+ $.fn.smartresize = function( fn ) {
309
+ return fn ? this.bind( "smartresize", fn ) : this.trigger( "smartresize", ["execAsap"] );
310
+ };
311
+
312
+
313
+
314
+ // ========================= Isotope ===============================
315
+
316
+
317
+ // our "Widget" object constructor
318
+ $.Isotope = function( options, element, callback ){
319
+ this.element = $( element );
320
+
321
+ this._create( options );
322
+ this._init( callback );
323
+ };
324
+
325
+ // styles of container element we want to keep track of
326
+ var isoContainerStyles = [ 'width', 'height' ];
327
+
328
+ var $window = $(window);
329
+
330
+ $.Isotope.settings = {
331
+ resizable: true,
332
+ layoutMode : 'masonry',
333
+ containerClass : 'isotope',
334
+ itemClass : 'isotope-item',
335
+ hiddenClass : 'isotope-hidden',
336
+ hiddenStyle: { opacity: 0, scale: 0.001 },
337
+ visibleStyle: { opacity: 1, scale: 1 },
338
+ containerStyle: {
339
+ position: 'relative',
340
+ overflow: 'hidden'
341
+ },
342
+ animationEngine: 'best-available',
343
+ animationOptions: {
344
+ queue: false,
345
+ duration: 800
346
+ },
347
+ sortBy : 'original-order',
348
+ sortAscending : true,
349
+ resizesContainer : true,
350
+ transformsEnabled: true,
351
+ itemPositionDataEnabled: false
352
+ };
353
+
354
+ $.Isotope.prototype = {
355
+
356
+ // sets up widget
357
+ _create : function( options ) {
358
+
359
+ this.options = $.extend( {}, $.Isotope.settings, options );
360
+
361
+ this.styleQueue = [];
362
+ this.elemCount = 0;
363
+
364
+ // get original styles in case we re-apply them in .destroy()
365
+ var elemStyle = this.element[0].style;
366
+ this.originalStyle = {};
367
+ // keep track of container styles
368
+ var containerStyles = isoContainerStyles.slice(0);
369
+ for ( var prop in this.options.containerStyle ) {
370
+ containerStyles.push( prop );
371
+ }
372
+ for ( var i=0, len = containerStyles.length; i < len; i++ ) {
373
+ prop = containerStyles[i];
374
+ this.originalStyle[ prop ] = elemStyle[ prop ] || '';
375
+ }
376
+ // apply container style from options
377
+ this.element.css( this.options.containerStyle );
378
+
379
+ this._updateAnimationEngine();
380
+ this._updateUsingTransforms();
381
+
382
+ // sorting
383
+ var originalOrderSorter = {
384
+ 'original-order' : function( $elem, instance ) {
385
+ instance.elemCount ++;
386
+ return instance.elemCount;
387
+ },
388
+ random : function() {
389
+ return Math.random();
390
+ }
391
+ };
392
+
393
+ this.options.getSortData = $.extend( this.options.getSortData, originalOrderSorter );
394
+
395
+ // need to get atoms
396
+ this.reloadItems();
397
+
398
+ // get top left position of where the bricks should be
399
+ this.offset = {
400
+ left: parseInt( ( this.element.css('padding-left') || 0 ), 10 ),
401
+ top: parseInt( ( this.element.css('padding-top') || 0 ), 10 )
402
+ };
403
+
404
+ // add isotope class first time around
405
+ var instance = this;
406
+ setTimeout( function() {
407
+ instance.element.addClass( instance.options.containerClass );
408
+ }, 0 );
409
+
410
+ // bind resize method
411
+ if ( this.options.resizable ) {
412
+ $window.bind( 'smartresize.isotope', function() {
413
+ instance.resize();
414
+ });
415
+ }
416
+
417
+ // dismiss all click events from hidden events
418
+ this.element.delegate( '.' + this.options.hiddenClass, 'click', function(){
419
+ return false;
420
+ });
421
+
422
+ },
423
+
424
+ _getAtoms : function( $elems ) {
425
+ var selector = this.options.itemSelector,
426
+ // filter & find
427
+ $atoms = selector ? $elems.filter( selector ).add( $elems.find( selector ) ) : $elems,
428
+ // base style for atoms
429
+ atomStyle = { position: 'absolute' };
430
+
431
+ // filter out text nodes
432
+ $atoms = $atoms.filter( function( i, atom ) {
433
+ return atom.nodeType === 1;
434
+ });
435
+
436
+ if ( this.usingTransforms ) {
437
+ atomStyle.left = 0;
438
+ atomStyle.top = 0;
439
+ }
440
+
441
+ $atoms.css( atomStyle ).addClass( this.options.itemClass );
442
+
443
+ this.updateSortData( $atoms, true );
444
+
445
+ return $atoms;
446
+ },
447
+
448
+ // _init fires when your instance is first created
449
+ // (from the constructor above), and when you
450
+ // attempt to initialize the widget again (by the bridge)
451
+ // after it has already been initialized.
452
+ _init : function( callback ) {
453
+
454
+ this.$filteredAtoms = this._filter( this.$allAtoms );
455
+ this._sort();
456
+ this.reLayout( callback );
457
+
458
+ },
459
+
460
+ option : function( opts ){
461
+ // change options AFTER initialization:
462
+ // signature: $('#foo').bar({ cool:false });
463
+ if ( $.isPlainObject( opts ) ){
464
+ this.options = $.extend( true, this.options, opts );
465
+
466
+ // trigger _updateOptionName if it exists
467
+ var updateOptionFn;
468
+ for ( var optionName in opts ) {
469
+ updateOptionFn = '_update' + capitalize( optionName );
470
+ if ( this[ updateOptionFn ] ) {
471
+ this[ updateOptionFn ]();
472
+ }
473
+ }
474
+ }
475
+ },
476
+
477
+ // ====================== updaters ====================== //
478
+ // kind of like setters
479
+
480
+ _updateAnimationEngine : function() {
481
+ var animationEngine = this.options.animationEngine.toLowerCase().replace( /[ _\-]/g, '');
482
+ var isUsingJQueryAnimation;
483
+ // set applyStyleFnName
484
+ switch ( animationEngine ) {
485
+ case 'css' :
486
+ case 'none' :
487
+ isUsingJQueryAnimation = false;
488
+ break;
489
+ case 'jquery' :
490
+ isUsingJQueryAnimation = true;
491
+ break;
492
+ default : // best available
493
+ isUsingJQueryAnimation = !Modernizr.csstransitions;
494
+ }
495
+ this.isUsingJQueryAnimation = isUsingJQueryAnimation;
496
+ this._updateUsingTransforms();
497
+ },
498
+
499
+ _updateTransformsEnabled : function() {
500
+ this._updateUsingTransforms();
501
+ },
502
+
503
+ _updateUsingTransforms : function() {
504
+ var usingTransforms = this.usingTransforms = this.options.transformsEnabled &&
505
+ Modernizr.csstransforms && Modernizr.csstransitions && !this.isUsingJQueryAnimation;
506
+
507
+ // prevent scales when transforms are disabled
508
+ if ( !usingTransforms ) {
509
+ delete this.options.hiddenStyle.scale;
510
+ delete this.options.visibleStyle.scale;
511
+ }
512
+
513
+ this.getPositionStyles = usingTransforms ? this._translate : this._positionAbs;
514
+ },
515
+
516
+
517
+ // ====================== Filtering ======================
518
+
519
+ _filter : function( $atoms ) {
520
+ var filter = this.options.filter === '' ? '*' : this.options.filter;
521
+
522
+ if ( !filter ) {
523
+ return $atoms;
524
+ }
525
+
526
+ var hiddenClass = this.options.hiddenClass,
527
+ hiddenSelector = '.' + hiddenClass,
528
+ $hiddenAtoms = $atoms.filter( hiddenSelector ),
529
+ $atomsToShow = $hiddenAtoms;
530
+
531
+ if ( filter !== '*' ) {
532
+ $atomsToShow = $hiddenAtoms.filter( filter );
533
+ var $atomsToHide = $atoms.not( hiddenSelector ).not( filter ).addClass( hiddenClass );
534
+ this.styleQueue.push({ $el: $atomsToHide, style: this.options.hiddenStyle });
535
+ }
536
+
537
+ this.styleQueue.push({ $el: $atomsToShow, style: this.options.visibleStyle });
538
+ $atomsToShow.removeClass( hiddenClass );
539
+
540
+ return $atoms.filter( filter );
541
+ },
542
+
543
+ // ====================== Sorting ======================
544
+
545
+ updateSortData : function( $atoms, isIncrementingElemCount ) {
546
+ var instance = this,
547
+ getSortData = this.options.getSortData,
548
+ $this, sortData;
549
+ $atoms.each(function(){
550
+ $this = $(this);
551
+ sortData = {};
552
+ // get value for sort data based on fn( $elem ) passed in
553
+ for ( var key in getSortData ) {
554
+ if ( !isIncrementingElemCount && key === 'original-order' ) {
555
+ // keep original order original
556
+ sortData[ key ] = $.data( this, 'isotope-sort-data' )[ key ];
557
+ } else {
558
+ sortData[ key ] = getSortData[ key ]( $this, instance );
559
+ }
560
+ }
561
+ // apply sort data to element
562
+ $.data( this, 'isotope-sort-data', sortData );
563
+ });
564
+ },
565
+
566
+ // used on all the filtered atoms
567
+ _sort : function() {
568
+
569
+ var sortBy = this.options.sortBy,
570
+ getSorter = this._getSorter,
571
+ sortDir = this.options.sortAscending ? 1 : -1,
572
+ sortFn = function( alpha, beta ) {
573
+ var a = getSorter( alpha, sortBy ),
574
+ b = getSorter( beta, sortBy );
575
+ // fall back to original order if data matches
576
+ if ( a === b && sortBy !== 'original-order') {
577
+ a = getSorter( alpha, 'original-order' );
578
+ b = getSorter( beta, 'original-order' );
579
+ }
580
+ return ( ( a > b ) ? 1 : ( a < b ) ? -1 : 0 ) * sortDir;
581
+ };
582
+
583
+ this.$filteredAtoms.sort( sortFn );
584
+ },
585
+
586
+ _getSorter : function( elem, sortBy ) {
587
+ return $.data( elem, 'isotope-sort-data' )[ sortBy ];
588
+ },
589
+
590
+ // ====================== Layout Helpers ======================
591
+
592
+ _translate : function( x, y ) {
593
+ return { translate : [ x, y ] };
594
+ },
595
+
596
+ _positionAbs : function( x, y ) {
597
+ return { left: x, top: y };
598
+ },
599
+
600
+ _pushPosition : function( $elem, x, y ) {
601
+ x = Math.round( x + this.offset.left );
602
+ y = Math.round( y + this.offset.top );
603
+ var position = this.getPositionStyles( x, y );
604
+ this.styleQueue.push({ $el: $elem, style: position });
605
+ if ( this.options.itemPositionDataEnabled ) {
606
+ $elem.data('isotope-item-position', {x: x, y: y} );
607
+ }
608
+ },
609
+
610
+
611
+ // ====================== General Layout ======================
612
+
613
+ // used on collection of atoms (should be filtered, and sorted before )
614
+ // accepts atoms-to-be-laid-out to start with
615
+ layout : function( $elems, callback ) {
616
+
617
+ var layoutMode = this.options.layoutMode;
618
+
619
+ // layout logic
620
+ this[ '_' + layoutMode + 'Layout' ]( $elems );
621
+
622
+ // set the size of the container
623
+ if ( this.options.resizesContainer ) {
624
+ var containerStyle = this[ '_' + layoutMode + 'GetContainerSize' ]();
625
+ this.styleQueue.push({ $el: this.element, style: containerStyle });
626
+ }
627
+
628
+ this._processStyleQueue( $elems, callback );
629
+
630
+ this.isLaidOut = true;
631
+ },
632
+
633
+ _processStyleQueue : function( $elems, callback ) {
634
+ // are we animating the layout arrangement?
635
+ // use plugin-ish syntax for css or animate
636
+ var styleFn = !this.isLaidOut ? 'css' : (
637
+ this.isUsingJQueryAnimation ? 'animate' : 'css'
638
+ ),
639
+ animOpts = this.options.animationOptions,
640
+ onLayout = this.options.onLayout,
641
+ objStyleFn, processor,
642
+ triggerCallbackNow, callbackFn;
643
+
644
+ // default styleQueue processor, may be overwritten down below
645
+ processor = function( i, obj ) {
646
+ obj.$el[ styleFn ]( obj.style, animOpts );
647
+ };
648
+
649
+ if ( this._isInserting && this.isUsingJQueryAnimation ) {
650
+ // if using styleQueue to insert items
651
+ processor = function( i, obj ) {
652
+ // only animate if it not being inserted
653
+ objStyleFn = obj.$el.hasClass('no-transition') ? 'css' : styleFn;
654
+ obj.$el[ objStyleFn ]( obj.style, animOpts );
655
+ };
656
+
657
+ } else if ( callback || onLayout || animOpts.complete ) {
658
+ // has callback
659
+ var isCallbackTriggered = false,
660
+ // array of possible callbacks to trigger
661
+ callbacks = [ callback, onLayout, animOpts.complete ],
662
+ instance = this;
663
+ triggerCallbackNow = true;
664
+ // trigger callback only once
665
+ callbackFn = function() {
666
+ if ( isCallbackTriggered ) {
667
+ return;
668
+ }
669
+ var hollaback;
670
+ for (var i=0, len = callbacks.length; i < len; i++) {
671
+ hollaback = callbacks[i];
672
+ if ( typeof hollaback === 'function' ) {
673
+ hollaback.call( instance.element, $elems, instance );
674
+ }
675
+ }
676
+ isCallbackTriggered = true;
677
+ };
678
+
679
+ if ( this.isUsingJQueryAnimation && styleFn === 'animate' ) {
680
+ // add callback to animation options
681
+ animOpts.complete = callbackFn;
682
+ triggerCallbackNow = false;
683
+
684
+ } else if ( Modernizr.csstransitions ) {
685
+ // detect if first item has transition
686
+ var i = 0,
687
+ firstItem = this.styleQueue[0],
688
+ testElem = firstItem && firstItem.$el,
689
+ styleObj;
690
+ // get first non-empty jQ object
691
+ while ( !testElem || !testElem.length ) {
692
+ styleObj = this.styleQueue[ i++ ];
693
+ // HACK: sometimes styleQueue[i] is undefined
694
+ if ( !styleObj ) {
695
+ return;
696
+ }
697
+ testElem = styleObj.$el;
698
+ }
699
+ // get transition duration of the first element in that object
700
+ // yeah, this is inexact
701
+ var duration = parseFloat( getComputedStyle( testElem[0] )[ transitionDurProp ] );
702
+ if ( duration > 0 ) {
703
+ processor = function( i, obj ) {
704
+ obj.$el[ styleFn ]( obj.style, animOpts )
705
+ // trigger callback at transition end
706
+ .one( transitionEndEvent, callbackFn );
707
+ };
708
+ triggerCallbackNow = false;
709
+ }
710
+ }
711
+ }
712
+
713
+ // process styleQueue
714
+ $.each( this.styleQueue, processor );
715
+
716
+ if ( triggerCallbackNow ) {
717
+ callbackFn();
718
+ }
719
+
720
+ // clear out queue for next time
721
+ this.styleQueue = [];
722
+ },
723
+
724
+
725
+ resize : function() {
726
+ if ( this[ '_' + this.options.layoutMode + 'ResizeChanged' ]() ) {
727
+ this.reLayout();
728
+ }
729
+ },
730
+
731
+
732
+ reLayout : function( callback ) {
733
+
734
+ this[ '_' + this.options.layoutMode + 'Reset' ]();
735
+ this.layout( this.$filteredAtoms, callback );
736
+
737
+ },
738
+
739
+ // ====================== Convenience methods ======================
740
+
741
+ // ====================== Adding items ======================
742
+
743
+ // adds a jQuery object of items to a isotope container
744
+ addItems : function( $content, callback ) {
745
+ var $newAtoms = this._getAtoms( $content );
746
+ // add new atoms to atoms pools
747
+ this.$allAtoms = this.$allAtoms.add( $newAtoms );
748
+
749
+ if ( callback ) {
750
+ callback( $newAtoms );
751
+ }
752
+ },
753
+
754
+ // convienence method for adding elements properly to any layout
755
+ // positions items, hides them, then animates them back in <--- very sezzy
756
+ insert : function( $content, callback ) {
757
+ // position items
758
+ this.element.append( $content );
759
+
760
+ var instance = this;
761
+ this.addItems( $content, function( $newAtoms ) {
762
+ var $newFilteredAtoms = instance._filter( $newAtoms );
763
+ instance._addHideAppended( $newFilteredAtoms );
764
+ instance._sort();
765
+ instance.reLayout();
766
+ instance._revealAppended( $newFilteredAtoms, callback );
767
+ });
768
+
769
+ },
770
+
771
+ // convienence method for working with Infinite Scroll
772
+ appended : function( $content, callback ) {
773
+ var instance = this;
774
+ this.addItems( $content, function( $newAtoms ) {
775
+ instance._addHideAppended( $newAtoms );
776
+ instance.layout( $newAtoms );
777
+ instance._revealAppended( $newAtoms, callback );
778
+ });
779
+ },
780
+
781
+ // adds new atoms, then hides them before positioning
782
+ _addHideAppended : function( $newAtoms ) {
783
+ this.$filteredAtoms = this.$filteredAtoms.add( $newAtoms );
784
+ $newAtoms.addClass('no-transition');
785
+
786
+ this._isInserting = true;
787
+
788
+ // apply hidden styles
789
+ this.styleQueue.push({ $el: $newAtoms, style: this.options.hiddenStyle });
790
+ },
791
+
792
+ // sets visible style on new atoms
793
+ _revealAppended : function( $newAtoms, callback ) {
794
+ var instance = this;
795
+ // apply visible style after a sec
796
+ setTimeout( function() {
797
+ // enable animation
798
+ $newAtoms.removeClass('no-transition');
799
+ // reveal newly inserted filtered elements
800
+ instance.styleQueue.push({ $el: $newAtoms, style: instance.options.visibleStyle });
801
+ instance._isInserting = false;
802
+ instance._processStyleQueue( $newAtoms, callback );
803
+ }, 10 );
804
+ },
805
+
806
+ // gathers all atoms
807
+ reloadItems : function() {
808
+ this.$allAtoms = this._getAtoms( this.element.children() );
809
+ },
810
+
811
+ // removes elements from Isotope widget
812
+ remove: function( $content, callback ) {
813
+ // remove elements immediately from Isotope instance
814
+ this.$allAtoms = this.$allAtoms.not( $content );
815
+ this.$filteredAtoms = this.$filteredAtoms.not( $content );
816
+ // remove() as a callback, for after transition / animation
817
+ var instance = this;
818
+ var removeContent = function() {
819
+ $content.remove();
820
+ if ( callback ) {
821
+ callback.call( instance.element );
822
+ }
823
+ };
824
+
825
+ if ( $content.filter( ':not(.' + this.options.hiddenClass + ')' ).length ) {
826
+ // if any non-hidden content needs to be removed
827
+ this.styleQueue.push({ $el: $content, style: this.options.hiddenStyle });
828
+ this._sort();
829
+ this.reLayout( removeContent );
830
+ } else {
831
+ // remove it now
832
+ removeContent();
833
+ }
834
+
835
+ },
836
+
837
+ shuffle : function( callback ) {
838
+ this.updateSortData( this.$allAtoms );
839
+ this.options.sortBy = 'random';
840
+ this._sort();
841
+ this.reLayout( callback );
842
+ },
843
+
844
+ // destroys widget, returns elements and container back (close) to original style
845
+ destroy : function() {
846
+
847
+ var usingTransforms = this.usingTransforms;
848
+ var options = this.options;
849
+
850
+ this.$allAtoms
851
+ .removeClass( options.hiddenClass + ' ' + options.itemClass )
852
+ .each(function(){
853
+ var style = this.style;
854
+ style.position = '';
855
+ style.top = '';
856
+ style.left = '';
857
+ style.opacity = '';
858
+ if ( usingTransforms ) {
859
+ style[ transformProp ] = '';
860
+ }
861
+ });
862
+
863
+ // re-apply saved container styles
864
+ var elemStyle = this.element[0].style;
865
+ for ( var prop in this.originalStyle ) {
866
+ elemStyle[ prop ] = this.originalStyle[ prop ];
867
+ }
868
+
869
+ this.element
870
+ .unbind('.isotope')
871
+ .undelegate( '.' + options.hiddenClass, 'click' )
872
+ .removeClass( options.containerClass )
873
+ .removeData('isotope');
874
+
875
+ $window.unbind('.isotope');
876
+
877
+ },
878
+
879
+
880
+ // ====================== LAYOUTS ======================
881
+
882
+ // calculates number of rows or columns
883
+ // requires columnWidth or rowHeight to be set on namespaced object
884
+ // i.e. this.masonry.columnWidth = 200
885
+ _getSegments : function( isRows ) {
886
+ var namespace = this.options.layoutMode,
887
+ measure = isRows ? 'rowHeight' : 'columnWidth',
888
+ size = isRows ? 'height' : 'width',
889
+ segmentsName = isRows ? 'rows' : 'cols',
890
+ containerSize = this.element[ size ](),
891
+ segments,
892
+ // i.e. options.masonry && options.masonry.columnWidth
893
+ segmentSize = this.options[ namespace ] && this.options[ namespace ][ measure ] ||
894
+ // or use the size of the first item, i.e. outerWidth
895
+ this.$filteredAtoms[ 'outer' + capitalize(size) ](true) ||
896
+ // if there's no items, use size of container
897
+ containerSize;
898
+
899
+ segments = Math.floor( containerSize / segmentSize );
900
+ segments = Math.max( segments, 1 );
901
+
902
+ // i.e. this.masonry.cols = ....
903
+ this[ namespace ][ segmentsName ] = segments;
904
+ // i.e. this.masonry.columnWidth = ...
905
+ this[ namespace ][ measure ] = segmentSize;
906
+
907
+ },
908
+
909
+ _checkIfSegmentsChanged : function( isRows ) {
910
+ var namespace = this.options.layoutMode,
911
+ segmentsName = isRows ? 'rows' : 'cols',
912
+ prevSegments = this[ namespace ][ segmentsName ];
913
+ // update cols/rows
914
+ this._getSegments( isRows );
915
+ // return if updated cols/rows is not equal to previous
916
+ return ( this[ namespace ][ segmentsName ] !== prevSegments );
917
+ },
918
+
919
+ // ====================== Masonry ======================
920
+
921
+ _masonryReset : function() {
922
+ // layout-specific props
923
+ this.masonry = {};
924
+ // FIXME shouldn't have to call this again
925
+ this._getSegments();
926
+ var i = this.masonry.cols;
927
+ this.masonry.colYs = [];
928
+ while (i--) {
929
+ this.masonry.colYs.push( 0 );
930
+ }
931
+ },
932
+
933
+ _masonryLayout : function( $elems ) {
934
+ var instance = this,
935
+ props = instance.masonry;
936
+ $elems.each(function(){
937
+ var $this = $(this),
938
+ //how many columns does this brick span
939
+ colSpan = Math.ceil( $this.outerWidth(true) / props.columnWidth );
940
+ colSpan = Math.min( colSpan, props.cols );
941
+
942
+ if ( colSpan === 1 ) {
943
+ // if brick spans only one column, just like singleMode
944
+ instance._masonryPlaceBrick( $this, props.colYs );
945
+ } else {
946
+ // brick spans more than one column
947
+ // how many different places could this brick fit horizontally
948
+ var groupCount = props.cols + 1 - colSpan,
949
+ groupY = [],
950
+ groupColY,
951
+ i;
952
+
953
+ // for each group potential horizontal position
954
+ for ( i=0; i < groupCount; i++ ) {
955
+ // make an array of colY values for that one group
956
+ groupColY = props.colYs.slice( i, i+colSpan );
957
+ // and get the max value of the array
958
+ groupY[i] = Math.max.apply( Math, groupColY );
959
+ }
960
+
961
+ instance._masonryPlaceBrick( $this, groupY );
962
+ }
963
+ });
964
+ },
965
+
966
+ // worker method that places brick in the columnSet
967
+ // with the the minY
968
+ _masonryPlaceBrick : function( $brick, setY ) {
969
+ // get the minimum Y value from the columns
970
+ var minimumY = Math.min.apply( Math, setY ),
971
+ shortCol = 0;
972
+
973
+ // Find index of short column, the first from the left
974
+ for (var i=0, len = setY.length; i < len; i++) {
975
+ if ( setY[i] === minimumY ) {
976
+ shortCol = i;
977
+ break;
978
+ }
979
+ }
980
+
981
+ // position the brick
982
+ var x = this.masonry.columnWidth * shortCol,
983
+ y = minimumY;
984
+ this._pushPosition( $brick, x, y );
985
+
986
+ // apply setHeight to necessary columns
987
+ var setHeight = minimumY + $brick.outerHeight(true),
988
+ setSpan = this.masonry.cols + 1 - len;
989
+ for ( i=0; i < setSpan; i++ ) {
990
+ this.masonry.colYs[ shortCol + i ] = setHeight;
991
+ }
992
+
993
+ },
994
+
995
+ _masonryGetContainerSize : function() {
996
+ var containerHeight = Math.max.apply( Math, this.masonry.colYs );
997
+ return { height: containerHeight };
998
+ },
999
+
1000
+ _masonryResizeChanged : function() {
1001
+ return this._checkIfSegmentsChanged();
1002
+ },
1003
+
1004
+ // ====================== fitRows ======================
1005
+
1006
+ _fitRowsReset : function() {
1007
+ this.fitRows = {
1008
+ x : 0,
1009
+ y : 0,
1010
+ height : 0
1011
+ };
1012
+ },
1013
+
1014
+ _fitRowsLayout : function( $elems ) {
1015
+ var instance = this,
1016
+ containerWidth = this.element.width(),
1017
+ props = this.fitRows;
1018
+
1019
+ $elems.each( function() {
1020
+ var $this = $(this),
1021
+ atomW = $this.outerWidth(true),
1022
+ atomH = $this.outerHeight(true);
1023
+
1024
+ if ( props.x !== 0 && atomW + props.x > containerWidth ) {
1025
+ // if this element cannot fit in the current row
1026
+ props.x = 0;
1027
+ props.y = props.height;
1028
+ }
1029
+
1030
+ // position the atom
1031
+ instance._pushPosition( $this, props.x, props.y );
1032
+
1033
+ props.height = Math.max( props.y + atomH, props.height );
1034
+ props.x += atomW;
1035
+
1036
+ });
1037
+ },
1038
+
1039
+ _fitRowsGetContainerSize : function () {
1040
+ return { height : this.fitRows.height };
1041
+ },
1042
+
1043
+ _fitRowsResizeChanged : function() {
1044
+ return true;
1045
+ },
1046
+
1047
+
1048
+ // ====================== cellsByRow ======================
1049
+
1050
+ _cellsByRowReset : function() {
1051
+ this.cellsByRow = {
1052
+ index : 0
1053
+ };
1054
+ // get this.cellsByRow.columnWidth
1055
+ this._getSegments();
1056
+ // get this.cellsByRow.rowHeight
1057
+ this._getSegments(true);
1058
+ },
1059
+
1060
+ _cellsByRowLayout : function( $elems ) {
1061
+ var instance = this,
1062
+ props = this.cellsByRow;
1063
+ $elems.each( function(){
1064
+ var $this = $(this),
1065
+ col = props.index % props.cols,
1066
+ row = Math.floor( props.index / props.cols ),
1067
+ x = ( col + 0.5 ) * props.columnWidth - $this.outerWidth(true) / 2,
1068
+ y = ( row + 0.5 ) * props.rowHeight - $this.outerHeight(true) / 2;
1069
+ instance._pushPosition( $this, x, y );
1070
+ props.index ++;
1071
+ });
1072
+ },
1073
+
1074
+ _cellsByRowGetContainerSize : function() {
1075
+ return { height : Math.ceil( this.$filteredAtoms.length / this.cellsByRow.cols ) * this.cellsByRow.rowHeight + this.offset.top };
1076
+ },
1077
+
1078
+ _cellsByRowResizeChanged : function() {
1079
+ return this._checkIfSegmentsChanged();
1080
+ },
1081
+
1082
+
1083
+ // ====================== straightDown ======================
1084
+
1085
+ _straightDownReset : function() {
1086
+ this.straightDown = {
1087
+ y : 0
1088
+ };
1089
+ },
1090
+
1091
+ _straightDownLayout : function( $elems ) {
1092
+ var instance = this;
1093
+ $elems.each( function( i ){
1094
+ var $this = $(this);
1095
+ instance._pushPosition( $this, 0, instance.straightDown.y );
1096
+ instance.straightDown.y += $this.outerHeight(true);
1097
+ });
1098
+ },
1099
+
1100
+ _straightDownGetContainerSize : function() {
1101
+ return { height : this.straightDown.y };
1102
+ },
1103
+
1104
+ _straightDownResizeChanged : function() {
1105
+ return true;
1106
+ },
1107
+
1108
+
1109
+ // ====================== masonryHorizontal ======================
1110
+
1111
+ _masonryHorizontalReset : function() {
1112
+ // layout-specific props
1113
+ this.masonryHorizontal = {};
1114
+ // FIXME shouldn't have to call this again
1115
+ this._getSegments( true );
1116
+ var i = this.masonryHorizontal.rows;
1117
+ this.masonryHorizontal.rowXs = [];
1118
+ while (i--) {
1119
+ this.masonryHorizontal.rowXs.push( 0 );
1120
+ }
1121
+ },
1122
+
1123
+ _masonryHorizontalLayout : function( $elems ) {
1124
+ var instance = this,
1125
+ props = instance.masonryHorizontal;
1126
+ $elems.each(function(){
1127
+ var $this = $(this),
1128
+ //how many rows does this brick span
1129
+ rowSpan = Math.ceil( $this.outerHeight(true) / props.rowHeight );
1130
+ rowSpan = Math.min( rowSpan, props.rows );
1131
+
1132
+ if ( rowSpan === 1 ) {
1133
+ // if brick spans only one column, just like singleMode
1134
+ instance._masonryHorizontalPlaceBrick( $this, props.rowXs );
1135
+ } else {
1136
+ // brick spans more than one row
1137
+ // how many different places could this brick fit horizontally
1138
+ var groupCount = props.rows + 1 - rowSpan,
1139
+ groupX = [],
1140
+ groupRowX, i;
1141
+
1142
+ // for each group potential horizontal position
1143
+ for ( i=0; i < groupCount; i++ ) {
1144
+ // make an array of colY values for that one group
1145
+ groupRowX = props.rowXs.slice( i, i+rowSpan );
1146
+ // and get the max value of the array
1147
+ groupX[i] = Math.max.apply( Math, groupRowX );
1148
+ }
1149
+
1150
+ instance._masonryHorizontalPlaceBrick( $this, groupX );
1151
+ }
1152
+ });
1153
+ },
1154
+
1155
+ _masonryHorizontalPlaceBrick : function( $brick, setX ) {
1156
+ // get the minimum Y value from the columns
1157
+ var minimumX = Math.min.apply( Math, setX ),
1158
+ smallRow = 0;
1159
+ // Find index of smallest row, the first from the top
1160
+ for (var i=0, len = setX.length; i < len; i++) {
1161
+ if ( setX[i] === minimumX ) {
1162
+ smallRow = i;
1163
+ break;
1164
+ }
1165
+ }
1166
+
1167
+ // position the brick
1168
+ var x = minimumX,
1169
+ y = this.masonryHorizontal.rowHeight * smallRow;
1170
+ this._pushPosition( $brick, x, y );
1171
+
1172
+ // apply setHeight to necessary columns
1173
+ var setWidth = minimumX + $brick.outerWidth(true),
1174
+ setSpan = this.masonryHorizontal.rows + 1 - len;
1175
+ for ( i=0; i < setSpan; i++ ) {
1176
+ this.masonryHorizontal.rowXs[ smallRow + i ] = setWidth;
1177
+ }
1178
+ },
1179
+
1180
+ _masonryHorizontalGetContainerSize : function() {
1181
+ var containerWidth = Math.max.apply( Math, this.masonryHorizontal.rowXs );
1182
+ return { width: containerWidth };
1183
+ },
1184
+
1185
+ _masonryHorizontalResizeChanged : function() {
1186
+ return this._checkIfSegmentsChanged(true);
1187
+ },
1188
+
1189
+
1190
+ // ====================== fitColumns ======================
1191
+
1192
+ _fitColumnsReset : function() {
1193
+ this.fitColumns = {
1194
+ x : 0,
1195
+ y : 0,
1196
+ width : 0
1197
+ };
1198
+ },
1199
+
1200
+ _fitColumnsLayout : function( $elems ) {
1201
+ var instance = this,
1202
+ containerHeight = this.element.height(),
1203
+ props = this.fitColumns;
1204
+ $elems.each( function() {
1205
+ var $this = $(this),
1206
+ atomW = $this.outerWidth(true),
1207
+ atomH = $this.outerHeight(true);
1208
+
1209
+ if ( props.y !== 0 && atomH + props.y > containerHeight ) {
1210
+ // if this element cannot fit in the current column
1211
+ props.x = props.width;
1212
+ props.y = 0;
1213
+ }
1214
+
1215
+ // position the atom
1216
+ instance._pushPosition( $this, props.x, props.y );
1217
+
1218
+ props.width = Math.max( props.x + atomW, props.width );
1219
+ props.y += atomH;
1220
+
1221
+ });
1222
+ },
1223
+
1224
+ _fitColumnsGetContainerSize : function () {
1225
+ return { width : this.fitColumns.width };
1226
+ },
1227
+
1228
+ _fitColumnsResizeChanged : function() {
1229
+ return true;
1230
+ },
1231
+
1232
+
1233
+
1234
+ // ====================== cellsByColumn ======================
1235
+
1236
+ _cellsByColumnReset : function() {
1237
+ this.cellsByColumn = {
1238
+ index : 0
1239
+ };
1240
+ // get this.cellsByColumn.columnWidth
1241
+ this._getSegments();
1242
+ // get this.cellsByColumn.rowHeight
1243
+ this._getSegments(true);
1244
+ },
1245
+
1246
+ _cellsByColumnLayout : function( $elems ) {
1247
+ var instance = this,
1248
+ props = this.cellsByColumn;
1249
+ $elems.each( function(){
1250
+ var $this = $(this),
1251
+ col = Math.floor( props.index / props.rows ),
1252
+ row = props.index % props.rows,
1253
+ x = ( col + 0.5 ) * props.columnWidth - $this.outerWidth(true) / 2,
1254
+ y = ( row + 0.5 ) * props.rowHeight - $this.outerHeight(true) / 2;
1255
+ instance._pushPosition( $this, x, y );
1256
+ props.index ++;
1257
+ });
1258
+ },
1259
+
1260
+ _cellsByColumnGetContainerSize : function() {
1261
+ return { width : Math.ceil( this.$filteredAtoms.length / this.cellsByColumn.rows ) * this.cellsByColumn.columnWidth };
1262
+ },
1263
+
1264
+ _cellsByColumnResizeChanged : function() {
1265
+ return this._checkIfSegmentsChanged(true);
1266
+ },
1267
+
1268
+ // ====================== straightAcross ======================
1269
+
1270
+ _straightAcrossReset : function() {
1271
+ this.straightAcross = {
1272
+ x : 0
1273
+ };
1274
+ },
1275
+
1276
+ _straightAcrossLayout : function( $elems ) {
1277
+ var instance = this;
1278
+ $elems.each( function( i ){
1279
+ var $this = $(this);
1280
+ instance._pushPosition( $this, instance.straightAcross.x, 0 );
1281
+ instance.straightAcross.x += $this.outerWidth(true);
1282
+ });
1283
+ },
1284
+
1285
+ _straightAcrossGetContainerSize : function() {
1286
+ return { width : this.straightAcross.x };
1287
+ },
1288
+
1289
+ _straightAcrossResizeChanged : function() {
1290
+ return true;
1291
+ }
1292
+
1293
+ };
1294
+
1295
+
1296
+ // ======================= imagesLoaded Plugin ===============================
1297
+ /*!
1298
+ * jQuery imagesLoaded plugin v1.1.0
1299
+ * http://github.com/desandro/imagesloaded
1300
+ *
1301
+ * MIT License. by Paul Irish et al.
1302
+ */
1303
+
1304
+
1305
+ // $('#my-container').imagesLoaded(myFunction)
1306
+ // or
1307
+ // $('img').imagesLoaded(myFunction)
1308
+
1309
+ // execute a callback when all images have loaded.
1310
+ // needed because .load() doesn't work on cached images
1311
+
1312
+ // callback function gets image collection as argument
1313
+ // `this` is the container
1314
+
1315
+ $.fn.imagesLoaded = function( callback ) {
1316
+ var $this = this,
1317
+ $images = $this.find('img').add( $this.filter('img') ),
1318
+ len = $images.length,
1319
+ blank = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==',
1320
+ loaded = [];
1321
+
1322
+ function triggerCallback() {
1323
+ callback.call( $this, $images );
1324
+ }
1325
+
1326
+ function imgLoaded( event ) {
1327
+ var img = event.target;
1328
+ if ( img.src !== blank && $.inArray( img, loaded ) === -1 ){
1329
+ loaded.push( img );
1330
+ if ( --len <= 0 ){
1331
+ setTimeout( triggerCallback );
1332
+ $images.unbind( '.imagesLoaded', imgLoaded );
1333
+ }
1334
+ }
1335
+ }
1336
+
1337
+ // if no images, trigger immediately
1338
+ if ( !len ) {
1339
+ triggerCallback();
1340
+ }
1341
+
1342
+ $images.bind( 'load.imagesLoaded error.imagesLoaded', imgLoaded ).each( function() {
1343
+ // cached images don't fire load sometimes, so we reset src.
1344
+ var src = this.src;
1345
+ // webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f
1346
+ // data uri bypasses webkit log warning (thx doug jones)
1347
+ this.src = blank;
1348
+ this.src = src;
1349
+ });
1350
+
1351
+ return $this;
1352
+ };
1353
+
1354
+
1355
+ // helper function for logging errors
1356
+ // $.error breaks jQuery chaining
1357
+ var logError = function( message ) {
1358
+ if ( window.console ) {
1359
+ window.console.error( message );
1360
+ }
1361
+ };
1362
+
1363
+ // ======================= Plugin bridge ===============================
1364
+ // leverages data method to either create or return $.Isotope constructor
1365
+ // A bit from jQuery UI
1366
+ // https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js
1367
+ // A bit from jcarousel
1368
+ // https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js
1369
+
1370
+ $.fn.isotope = function( options, callback ) {
1371
+ if ( typeof options === 'string' ) {
1372
+ // call method
1373
+ var args = Array.prototype.slice.call( arguments, 1 );
1374
+
1375
+ this.each(function(){
1376
+ var instance = $.data( this, 'isotope' );
1377
+ if ( !instance ) {
1378
+ logError( "cannot call methods on isotope prior to initialization; " +
1379
+ "attempted to call method '" + options + "'" );
1380
+ return;
1381
+ }
1382
+ if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
1383
+ logError( "no such method '" + options + "' for isotope instance" );
1384
+ return;
1385
+ }
1386
+ // apply method
1387
+ instance[ options ].apply( instance, args );
1388
+ });
1389
+ } else {
1390
+ this.each(function() {
1391
+ var instance = $.data( this, 'isotope' );
1392
+ if ( instance ) {
1393
+ // apply options & init
1394
+ instance.option( options );
1395
+ instance._init( callback );
1396
+ } else {
1397
+ // initialize new instance
1398
+ $.data( this, 'isotope', new $.Isotope( options, this, callback ) );
1399
+ }
1400
+ });
1401
+ }
1402
+ // return jQuery object
1403
+ // so plugin methods do not have to
1404
+ return this;
1405
+ };
1406
+
1407
+ })( window, jQuery );