jquery-masonry-rails 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c43fbf13fb66c8da717725ea48a75c36ca8e048a
4
+ data.tar.gz: 6dba9bedc7c2832a469946cfece5239548870b51
5
+ SHA512:
6
+ metadata.gz: c0f12365939aa7b7a467126ad2278f1317c8d8a43fb99355a5b16c403e6617c2d70dd002b99d25a091a1be90d9e8dd1350ccbf78257a1f199e132a611f1a27e2
7
+ data.tar.gz: 007c4022681fa3dce902054d3e186b2410d4ea3a482f70f78fd42b6eb33a090637cae8daf7e6b43702497c93fd4c7598333fcd78f80111f578835aea3b3d0dd0
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jquery-masonry-rails.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Christian Dobert
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # Jquery::Masonry::Rails
2
+
3
+ This gem is a simple wrapper around the Masonry plugin.
4
+ It is bundled as a gem to be able to include this 3rd party asset into the asset pipeline, without having to locally import the actual CSS and JavaScript into your project.
5
+ Please see hhttp://masonry.desandro.com/ for the original plugin.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'jquery-masonry-rails'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install jquery-masonry-rails
20
+
21
+ ## Usage
22
+
23
+ 1. In your `app/assets/javascripts/application.js` include the following line:
24
+
25
+ `//= require masonry.pkgd`
26
+
27
+ For further HTML and CSS examples, please see: hhttp://masonry.desandro.com
28
+
29
+ ## Contributing
30
+
31
+ 1. Fork it ( https://github.com/dondope/jquery-masonry-rails/fork )
32
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
33
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
34
+ 4. Push to the branch (`git push origin my-new-feature`)
35
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'jquery/masonry/rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "jquery-masonry-rails"
8
+ spec.version = Jquery::Masonry::Rails::VERSION
9
+ spec.authors = ["Christian Dobert"]
10
+ spec.email = ["chr.dobert@gmail.com"]
11
+ spec.summary = %q{A simple asset wrapper for the masonry plugin.}
12
+ spec.description = %q{A simple asset wrapper for the masonry plugin. See http://masonry.desandro.com/}
13
+ spec.homepage = "https://github.com/dondope/jquery-masonry-rails"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake"
23
+ end
@@ -0,0 +1,10 @@
1
+ require "jquery/masonry/rails/version"
2
+
3
+ module Jquery
4
+ module Masonry
5
+ module Rails
6
+ class Engine < ::Rails::Engine
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ module Jquery
2
+ module Masonry
3
+ module Rails
4
+ VERSION = "3.0.2"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,2885 @@
1
+ /*!
2
+ * Masonry PACKAGED v3.1.5
3
+ * Cascading grid layout library
4
+ * http://masonry.desandro.com
5
+ * MIT License
6
+ * by David DeSandro
7
+ */
8
+
9
+ /**
10
+ * Bridget makes jQuery widgets
11
+ * v1.0.1
12
+ */
13
+
14
+ ( function( window ) {
15
+
16
+
17
+
18
+ // -------------------------- utils -------------------------- //
19
+
20
+ var slice = Array.prototype.slice;
21
+
22
+ function noop() {}
23
+
24
+ // -------------------------- definition -------------------------- //
25
+
26
+ function defineBridget( $ ) {
27
+
28
+ // bail if no jQuery
29
+ if ( !$ ) {
30
+ return;
31
+ }
32
+
33
+ // -------------------------- addOptionMethod -------------------------- //
34
+
35
+ /**
36
+ * adds option method -> $().plugin('option', {...})
37
+ * @param {Function} PluginClass - constructor class
38
+ */
39
+ function addOptionMethod( PluginClass ) {
40
+ // don't overwrite original option method
41
+ if ( PluginClass.prototype.option ) {
42
+ return;
43
+ }
44
+
45
+ // option setter
46
+ PluginClass.prototype.option = function( opts ) {
47
+ // bail out if not an object
48
+ if ( !$.isPlainObject( opts ) ){
49
+ return;
50
+ }
51
+ this.options = $.extend( true, this.options, opts );
52
+ };
53
+ }
54
+
55
+
56
+ // -------------------------- plugin bridge -------------------------- //
57
+
58
+ // helper function for logging errors
59
+ // $.error breaks jQuery chaining
60
+ var logError = typeof console === 'undefined' ? noop :
61
+ function( message ) {
62
+ console.error( message );
63
+ };
64
+
65
+ /**
66
+ * jQuery plugin bridge, access methods like $elem.plugin('method')
67
+ * @param {String} namespace - plugin name
68
+ * @param {Function} PluginClass - constructor class
69
+ */
70
+ function bridge( namespace, PluginClass ) {
71
+ // add to jQuery fn namespace
72
+ $.fn[ namespace ] = function( options ) {
73
+ if ( typeof options === 'string' ) {
74
+ // call plugin method when first argument is a string
75
+ // get arguments for method
76
+ var args = slice.call( arguments, 1 );
77
+
78
+ for ( var i=0, len = this.length; i < len; i++ ) {
79
+ var elem = this[i];
80
+ var instance = $.data( elem, namespace );
81
+ if ( !instance ) {
82
+ logError( "cannot call methods on " + namespace + " prior to initialization; " +
83
+ "attempted to call '" + options + "'" );
84
+ continue;
85
+ }
86
+ if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) {
87
+ logError( "no such method '" + options + "' for " + namespace + " instance" );
88
+ continue;
89
+ }
90
+
91
+ // trigger method with arguments
92
+ var returnValue = instance[ options ].apply( instance, args );
93
+
94
+ // break look and return first value if provided
95
+ if ( returnValue !== undefined ) {
96
+ return returnValue;
97
+ }
98
+ }
99
+ // return this if no return value
100
+ return this;
101
+ } else {
102
+ return this.each( function() {
103
+ var instance = $.data( this, namespace );
104
+ if ( instance ) {
105
+ // apply options & init
106
+ instance.option( options );
107
+ instance._init();
108
+ } else {
109
+ // initialize new instance
110
+ instance = new PluginClass( this, options );
111
+ $.data( this, namespace, instance );
112
+ }
113
+ });
114
+ }
115
+ };
116
+
117
+ }
118
+
119
+ // -------------------------- bridget -------------------------- //
120
+
121
+ /**
122
+ * converts a Prototypical class into a proper jQuery plugin
123
+ * the class must have a ._init method
124
+ * @param {String} namespace - plugin name, used in $().pluginName
125
+ * @param {Function} PluginClass - constructor class
126
+ */
127
+ $.bridget = function( namespace, PluginClass ) {
128
+ addOptionMethod( PluginClass );
129
+ bridge( namespace, PluginClass );
130
+ };
131
+
132
+ return $.bridget;
133
+
134
+ }
135
+
136
+ // transport
137
+ if ( typeof define === 'function' && define.amd ) {
138
+ // AMD
139
+ define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget );
140
+ } else {
141
+ // get jquery from browser global
142
+ defineBridget( window.jQuery );
143
+ }
144
+
145
+ })( window );
146
+
147
+ /*!
148
+ * eventie v1.0.5
149
+ * event binding helper
150
+ * eventie.bind( elem, 'click', myFn )
151
+ * eventie.unbind( elem, 'click', myFn )
152
+ * MIT license
153
+ */
154
+
155
+ /*jshint browser: true, undef: true, unused: true */
156
+ /*global define: false, module: false */
157
+
158
+ ( function( window ) {
159
+
160
+
161
+
162
+ var docElem = document.documentElement;
163
+
164
+ var bind = function() {};
165
+
166
+ function getIEEvent( obj ) {
167
+ var event = window.event;
168
+ // add event.target
169
+ event.target = event.target || event.srcElement || obj;
170
+ return event;
171
+ }
172
+
173
+ if ( docElem.addEventListener ) {
174
+ bind = function( obj, type, fn ) {
175
+ obj.addEventListener( type, fn, false );
176
+ };
177
+ } else if ( docElem.attachEvent ) {
178
+ bind = function( obj, type, fn ) {
179
+ obj[ type + fn ] = fn.handleEvent ?
180
+ function() {
181
+ var event = getIEEvent( obj );
182
+ fn.handleEvent.call( fn, event );
183
+ } :
184
+ function() {
185
+ var event = getIEEvent( obj );
186
+ fn.call( obj, event );
187
+ };
188
+ obj.attachEvent( "on" + type, obj[ type + fn ] );
189
+ };
190
+ }
191
+
192
+ var unbind = function() {};
193
+
194
+ if ( docElem.removeEventListener ) {
195
+ unbind = function( obj, type, fn ) {
196
+ obj.removeEventListener( type, fn, false );
197
+ };
198
+ } else if ( docElem.detachEvent ) {
199
+ unbind = function( obj, type, fn ) {
200
+ obj.detachEvent( "on" + type, obj[ type + fn ] );
201
+ try {
202
+ delete obj[ type + fn ];
203
+ } catch ( err ) {
204
+ // can't delete window object properties
205
+ obj[ type + fn ] = undefined;
206
+ }
207
+ };
208
+ }
209
+
210
+ var eventie = {
211
+ bind: bind,
212
+ unbind: unbind
213
+ };
214
+
215
+ // ----- module definition ----- //
216
+
217
+ if ( typeof define === 'function' && define.amd ) {
218
+ // AMD
219
+ define( 'eventie/eventie',eventie );
220
+ } else if ( typeof exports === 'object' ) {
221
+ // CommonJS
222
+ module.exports = eventie;
223
+ } else {
224
+ // browser global
225
+ window.eventie = eventie;
226
+ }
227
+
228
+ })( this );
229
+
230
+ /*!
231
+ * docReady
232
+ * Cross browser DOMContentLoaded event emitter
233
+ */
234
+
235
+ /*jshint browser: true, strict: true, undef: true, unused: true*/
236
+ /*global define: false */
237
+
238
+ ( function( window ) {
239
+
240
+
241
+
242
+ var document = window.document;
243
+ // collection of functions to be triggered on ready
244
+ var queue = [];
245
+
246
+ function docReady( fn ) {
247
+ // throw out non-functions
248
+ if ( typeof fn !== 'function' ) {
249
+ return;
250
+ }
251
+
252
+ if ( docReady.isReady ) {
253
+ // ready now, hit it
254
+ fn();
255
+ } else {
256
+ // queue function when ready
257
+ queue.push( fn );
258
+ }
259
+ }
260
+
261
+ docReady.isReady = false;
262
+
263
+ // triggered on various doc ready events
264
+ function init( event ) {
265
+ // bail if IE8 document is not ready just yet
266
+ var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete';
267
+ if ( docReady.isReady || isIE8NotReady ) {
268
+ return;
269
+ }
270
+ docReady.isReady = true;
271
+
272
+ // process queue
273
+ for ( var i=0, len = queue.length; i < len; i++ ) {
274
+ var fn = queue[i];
275
+ fn();
276
+ }
277
+ }
278
+
279
+ function defineDocReady( eventie ) {
280
+ eventie.bind( document, 'DOMContentLoaded', init );
281
+ eventie.bind( document, 'readystatechange', init );
282
+ eventie.bind( window, 'load', init );
283
+
284
+ return docReady;
285
+ }
286
+
287
+ // transport
288
+ if ( typeof define === 'function' && define.amd ) {
289
+ // AMD
290
+ // if RequireJS, then doc is already ready
291
+ docReady.isReady = typeof requirejs === 'function';
292
+ define( 'doc-ready/doc-ready',[ 'eventie/eventie' ], defineDocReady );
293
+ } else {
294
+ // browser global
295
+ window.docReady = defineDocReady( window.eventie );
296
+ }
297
+
298
+ })( this );
299
+
300
+ /*!
301
+ * EventEmitter v4.2.7 - git.io/ee
302
+ * Oliver Caldwell
303
+ * MIT license
304
+ * @preserve
305
+ */
306
+
307
+ (function () {
308
+
309
+
310
+ /**
311
+ * Class for managing events.
312
+ * Can be extended to provide event functionality in other classes.
313
+ *
314
+ * @class EventEmitter Manages event registering and emitting.
315
+ */
316
+ function EventEmitter() {}
317
+
318
+ // Shortcuts to improve speed and size
319
+ var proto = EventEmitter.prototype;
320
+ var exports = this;
321
+ var originalGlobalValue = exports.EventEmitter;
322
+
323
+ /**
324
+ * Finds the index of the listener for the event in it's storage array.
325
+ *
326
+ * @param {Function[]} listeners Array of listeners to search through.
327
+ * @param {Function} listener Method to look for.
328
+ * @return {Number} Index of the specified listener, -1 if not found
329
+ * @api private
330
+ */
331
+ function indexOfListener(listeners, listener) {
332
+ var i = listeners.length;
333
+ while (i--) {
334
+ if (listeners[i].listener === listener) {
335
+ return i;
336
+ }
337
+ }
338
+
339
+ return -1;
340
+ }
341
+
342
+ /**
343
+ * Alias a method while keeping the context correct, to allow for overwriting of target method.
344
+ *
345
+ * @param {String} name The name of the target method.
346
+ * @return {Function} The aliased method
347
+ * @api private
348
+ */
349
+ function alias(name) {
350
+ return function aliasClosure() {
351
+ return this[name].apply(this, arguments);
352
+ };
353
+ }
354
+
355
+ /**
356
+ * Returns the listener array for the specified event.
357
+ * Will initialise the event object and listener arrays if required.
358
+ * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.
359
+ * Each property in the object response is an array of listener functions.
360
+ *
361
+ * @param {String|RegExp} evt Name of the event to return the listeners from.
362
+ * @return {Function[]|Object} All listener functions for the event.
363
+ */
364
+ proto.getListeners = function getListeners(evt) {
365
+ var events = this._getEvents();
366
+ var response;
367
+ var key;
368
+
369
+ // Return a concatenated array of all matching events if
370
+ // the selector is a regular expression.
371
+ if (evt instanceof RegExp) {
372
+ response = {};
373
+ for (key in events) {
374
+ if (events.hasOwnProperty(key) && evt.test(key)) {
375
+ response[key] = events[key];
376
+ }
377
+ }
378
+ }
379
+ else {
380
+ response = events[evt] || (events[evt] = []);
381
+ }
382
+
383
+ return response;
384
+ };
385
+
386
+ /**
387
+ * Takes a list of listener objects and flattens it into a list of listener functions.
388
+ *
389
+ * @param {Object[]} listeners Raw listener objects.
390
+ * @return {Function[]} Just the listener functions.
391
+ */
392
+ proto.flattenListeners = function flattenListeners(listeners) {
393
+ var flatListeners = [];
394
+ var i;
395
+
396
+ for (i = 0; i < listeners.length; i += 1) {
397
+ flatListeners.push(listeners[i].listener);
398
+ }
399
+
400
+ return flatListeners;
401
+ };
402
+
403
+ /**
404
+ * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.
405
+ *
406
+ * @param {String|RegExp} evt Name of the event to return the listeners from.
407
+ * @return {Object} All listener functions for an event in an object.
408
+ */
409
+ proto.getListenersAsObject = function getListenersAsObject(evt) {
410
+ var listeners = this.getListeners(evt);
411
+ var response;
412
+
413
+ if (listeners instanceof Array) {
414
+ response = {};
415
+ response[evt] = listeners;
416
+ }
417
+
418
+ return response || listeners;
419
+ };
420
+
421
+ /**
422
+ * Adds a listener function to the specified event.
423
+ * The listener will not be added if it is a duplicate.
424
+ * If the listener returns true then it will be removed after it is called.
425
+ * If you pass a regular expression as the event name then the listener will be added to all events that match it.
426
+ *
427
+ * @param {String|RegExp} evt Name of the event to attach the listener to.
428
+ * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
429
+ * @return {Object} Current instance of EventEmitter for chaining.
430
+ */
431
+ proto.addListener = function addListener(evt, listener) {
432
+ var listeners = this.getListenersAsObject(evt);
433
+ var listenerIsWrapped = typeof listener === 'object';
434
+ var key;
435
+
436
+ for (key in listeners) {
437
+ if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
438
+ listeners[key].push(listenerIsWrapped ? listener : {
439
+ listener: listener,
440
+ once: false
441
+ });
442
+ }
443
+ }
444
+
445
+ return this;
446
+ };
447
+
448
+ /**
449
+ * Alias of addListener
450
+ */
451
+ proto.on = alias('addListener');
452
+
453
+ /**
454
+ * Semi-alias of addListener. It will add a listener that will be
455
+ * automatically removed after it's first execution.
456
+ *
457
+ * @param {String|RegExp} evt Name of the event to attach the listener to.
458
+ * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
459
+ * @return {Object} Current instance of EventEmitter for chaining.
460
+ */
461
+ proto.addOnceListener = function addOnceListener(evt, listener) {
462
+ return this.addListener(evt, {
463
+ listener: listener,
464
+ once: true
465
+ });
466
+ };
467
+
468
+ /**
469
+ * Alias of addOnceListener.
470
+ */
471
+ proto.once = alias('addOnceListener');
472
+
473
+ /**
474
+ * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.
475
+ * You need to tell it what event names should be matched by a regex.
476
+ *
477
+ * @param {String} evt Name of the event to create.
478
+ * @return {Object} Current instance of EventEmitter for chaining.
479
+ */
480
+ proto.defineEvent = function defineEvent(evt) {
481
+ this.getListeners(evt);
482
+ return this;
483
+ };
484
+
485
+ /**
486
+ * Uses defineEvent to define multiple events.
487
+ *
488
+ * @param {String[]} evts An array of event names to define.
489
+ * @return {Object} Current instance of EventEmitter for chaining.
490
+ */
491
+ proto.defineEvents = function defineEvents(evts) {
492
+ for (var i = 0; i < evts.length; i += 1) {
493
+ this.defineEvent(evts[i]);
494
+ }
495
+ return this;
496
+ };
497
+
498
+ /**
499
+ * Removes a listener function from the specified event.
500
+ * When passed a regular expression as the event name, it will remove the listener from all events that match it.
501
+ *
502
+ * @param {String|RegExp} evt Name of the event to remove the listener from.
503
+ * @param {Function} listener Method to remove from the event.
504
+ * @return {Object} Current instance of EventEmitter for chaining.
505
+ */
506
+ proto.removeListener = function removeListener(evt, listener) {
507
+ var listeners = this.getListenersAsObject(evt);
508
+ var index;
509
+ var key;
510
+
511
+ for (key in listeners) {
512
+ if (listeners.hasOwnProperty(key)) {
513
+ index = indexOfListener(listeners[key], listener);
514
+
515
+ if (index !== -1) {
516
+ listeners[key].splice(index, 1);
517
+ }
518
+ }
519
+ }
520
+
521
+ return this;
522
+ };
523
+
524
+ /**
525
+ * Alias of removeListener
526
+ */
527
+ proto.off = alias('removeListener');
528
+
529
+ /**
530
+ * Adds listeners in bulk using the manipulateListeners method.
531
+ * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.
532
+ * You can also pass it a regular expression to add the array of listeners to all events that match it.
533
+ * Yeah, this function does quite a bit. That's probably a bad thing.
534
+ *
535
+ * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.
536
+ * @param {Function[]} [listeners] An optional array of listener functions to add.
537
+ * @return {Object} Current instance of EventEmitter for chaining.
538
+ */
539
+ proto.addListeners = function addListeners(evt, listeners) {
540
+ // Pass through to manipulateListeners
541
+ return this.manipulateListeners(false, evt, listeners);
542
+ };
543
+
544
+ /**
545
+ * Removes listeners in bulk using the manipulateListeners method.
546
+ * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
547
+ * You can also pass it an event name and an array of listeners to be removed.
548
+ * You can also pass it a regular expression to remove the listeners from all events that match it.
549
+ *
550
+ * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.
551
+ * @param {Function[]} [listeners] An optional array of listener functions to remove.
552
+ * @return {Object} Current instance of EventEmitter for chaining.
553
+ */
554
+ proto.removeListeners = function removeListeners(evt, listeners) {
555
+ // Pass through to manipulateListeners
556
+ return this.manipulateListeners(true, evt, listeners);
557
+ };
558
+
559
+ /**
560
+ * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.
561
+ * The first argument will determine if the listeners are removed (true) or added (false).
562
+ * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.
563
+ * You can also pass it an event name and an array of listeners to be added/removed.
564
+ * You can also pass it a regular expression to manipulate the listeners of all events that match it.
565
+ *
566
+ * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
567
+ * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.
568
+ * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
569
+ * @return {Object} Current instance of EventEmitter for chaining.
570
+ */
571
+ proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
572
+ var i;
573
+ var value;
574
+ var single = remove ? this.removeListener : this.addListener;
575
+ var multiple = remove ? this.removeListeners : this.addListeners;
576
+
577
+ // If evt is an object then pass each of it's properties to this method
578
+ if (typeof evt === 'object' && !(evt instanceof RegExp)) {
579
+ for (i in evt) {
580
+ if (evt.hasOwnProperty(i) && (value = evt[i])) {
581
+ // Pass the single listener straight through to the singular method
582
+ if (typeof value === 'function') {
583
+ single.call(this, i, value);
584
+ }
585
+ else {
586
+ // Otherwise pass back to the multiple function
587
+ multiple.call(this, i, value);
588
+ }
589
+ }
590
+ }
591
+ }
592
+ else {
593
+ // So evt must be a string
594
+ // And listeners must be an array of listeners
595
+ // Loop over it and pass each one to the multiple method
596
+ i = listeners.length;
597
+ while (i--) {
598
+ single.call(this, evt, listeners[i]);
599
+ }
600
+ }
601
+
602
+ return this;
603
+ };
604
+
605
+ /**
606
+ * Removes all listeners from a specified event.
607
+ * If you do not specify an event then all listeners will be removed.
608
+ * That means every event will be emptied.
609
+ * You can also pass a regex to remove all events that match it.
610
+ *
611
+ * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
612
+ * @return {Object} Current instance of EventEmitter for chaining.
613
+ */
614
+ proto.removeEvent = function removeEvent(evt) {
615
+ var type = typeof evt;
616
+ var events = this._getEvents();
617
+ var key;
618
+
619
+ // Remove different things depending on the state of evt
620
+ if (type === 'string') {
621
+ // Remove all listeners for the specified event
622
+ delete events[evt];
623
+ }
624
+ else if (evt instanceof RegExp) {
625
+ // Remove all events matching the regex.
626
+ for (key in events) {
627
+ if (events.hasOwnProperty(key) && evt.test(key)) {
628
+ delete events[key];
629
+ }
630
+ }
631
+ }
632
+ else {
633
+ // Remove all listeners in all events
634
+ delete this._events;
635
+ }
636
+
637
+ return this;
638
+ };
639
+
640
+ /**
641
+ * Alias of removeEvent.
642
+ *
643
+ * Added to mirror the node API.
644
+ */
645
+ proto.removeAllListeners = alias('removeEvent');
646
+
647
+ /**
648
+ * Emits an event of your choice.
649
+ * When emitted, every listener attached to that event will be executed.
650
+ * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
651
+ * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
652
+ * So they will not arrive within the array on the other side, they will be separate.
653
+ * You can also pass a regular expression to emit to all events that match it.
654
+ *
655
+ * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
656
+ * @param {Array} [args] Optional array of arguments to be passed to each listener.
657
+ * @return {Object} Current instance of EventEmitter for chaining.
658
+ */
659
+ proto.emitEvent = function emitEvent(evt, args) {
660
+ var listeners = this.getListenersAsObject(evt);
661
+ var listener;
662
+ var i;
663
+ var key;
664
+ var response;
665
+
666
+ for (key in listeners) {
667
+ if (listeners.hasOwnProperty(key)) {
668
+ i = listeners[key].length;
669
+
670
+ while (i--) {
671
+ // If the listener returns true then it shall be removed from the event
672
+ // The function is executed either with a basic call or an apply if there is an args array
673
+ listener = listeners[key][i];
674
+
675
+ if (listener.once === true) {
676
+ this.removeListener(evt, listener.listener);
677
+ }
678
+
679
+ response = listener.listener.apply(this, args || []);
680
+
681
+ if (response === this._getOnceReturnValue()) {
682
+ this.removeListener(evt, listener.listener);
683
+ }
684
+ }
685
+ }
686
+ }
687
+
688
+ return this;
689
+ };
690
+
691
+ /**
692
+ * Alias of emitEvent
693
+ */
694
+ proto.trigger = alias('emitEvent');
695
+
696
+ /**
697
+ * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.
698
+ * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
699
+ *
700
+ * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
701
+ * @param {...*} Optional additional arguments to be passed to each listener.
702
+ * @return {Object} Current instance of EventEmitter for chaining.
703
+ */
704
+ proto.emit = function emit(evt) {
705
+ var args = Array.prototype.slice.call(arguments, 1);
706
+ return this.emitEvent(evt, args);
707
+ };
708
+
709
+ /**
710
+ * Sets the current value to check against when executing listeners. If a
711
+ * listeners return value matches the one set here then it will be removed
712
+ * after execution. This value defaults to true.
713
+ *
714
+ * @param {*} value The new value to check for when executing listeners.
715
+ * @return {Object} Current instance of EventEmitter for chaining.
716
+ */
717
+ proto.setOnceReturnValue = function setOnceReturnValue(value) {
718
+ this._onceReturnValue = value;
719
+ return this;
720
+ };
721
+
722
+ /**
723
+ * Fetches the current value to check against when executing listeners. If
724
+ * the listeners return value matches this one then it should be removed
725
+ * automatically. It will return true by default.
726
+ *
727
+ * @return {*|Boolean} The current value to check for or the default, true.
728
+ * @api private
729
+ */
730
+ proto._getOnceReturnValue = function _getOnceReturnValue() {
731
+ if (this.hasOwnProperty('_onceReturnValue')) {
732
+ return this._onceReturnValue;
733
+ }
734
+ else {
735
+ return true;
736
+ }
737
+ };
738
+
739
+ /**
740
+ * Fetches the events object and creates one if required.
741
+ *
742
+ * @return {Object} The events storage object.
743
+ * @api private
744
+ */
745
+ proto._getEvents = function _getEvents() {
746
+ return this._events || (this._events = {});
747
+ };
748
+
749
+ /**
750
+ * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
751
+ *
752
+ * @return {Function} Non conflicting EventEmitter class.
753
+ */
754
+ EventEmitter.noConflict = function noConflict() {
755
+ exports.EventEmitter = originalGlobalValue;
756
+ return EventEmitter;
757
+ };
758
+
759
+ // Expose the class either via AMD, CommonJS or the global object
760
+ if (typeof define === 'function' && define.amd) {
761
+ define('eventEmitter/EventEmitter',[],function () {
762
+ return EventEmitter;
763
+ });
764
+ }
765
+ else if (typeof module === 'object' && module.exports){
766
+ module.exports = EventEmitter;
767
+ }
768
+ else {
769
+ this.EventEmitter = EventEmitter;
770
+ }
771
+ }.call(this));
772
+
773
+ /*!
774
+ * getStyleProperty v1.0.3
775
+ * original by kangax
776
+ * http://perfectionkills.com/feature-testing-css-properties/
777
+ */
778
+
779
+ /*jshint browser: true, strict: true, undef: true */
780
+ /*global define: false, exports: false, module: false */
781
+
782
+ ( function( window ) {
783
+
784
+
785
+
786
+ var prefixes = 'Webkit Moz ms Ms O'.split(' ');
787
+ var docElemStyle = document.documentElement.style;
788
+
789
+ function getStyleProperty( propName ) {
790
+ if ( !propName ) {
791
+ return;
792
+ }
793
+
794
+ // test standard property first
795
+ if ( typeof docElemStyle[ propName ] === 'string' ) {
796
+ return propName;
797
+ }
798
+
799
+ // capitalize
800
+ propName = propName.charAt(0).toUpperCase() + propName.slice(1);
801
+
802
+ // test vendor specific properties
803
+ var prefixed;
804
+ for ( var i=0, len = prefixes.length; i < len; i++ ) {
805
+ prefixed = prefixes[i] + propName;
806
+ if ( typeof docElemStyle[ prefixed ] === 'string' ) {
807
+ return prefixed;
808
+ }
809
+ }
810
+ }
811
+
812
+ // transport
813
+ if ( typeof define === 'function' && define.amd ) {
814
+ // AMD
815
+ define( 'get-style-property/get-style-property',[],function() {
816
+ return getStyleProperty;
817
+ });
818
+ } else if ( typeof exports === 'object' ) {
819
+ // CommonJS for Component
820
+ module.exports = getStyleProperty;
821
+ } else {
822
+ // browser global
823
+ window.getStyleProperty = getStyleProperty;
824
+ }
825
+
826
+ })( window );
827
+
828
+ /**
829
+ * getSize v1.1.7
830
+ * measure size of elements
831
+ */
832
+
833
+ /*jshint browser: true, strict: true, undef: true, unused: true */
834
+ /*global define: false, exports: false, require: false, module: false */
835
+
836
+ ( function( window, undefined ) {
837
+
838
+
839
+
840
+ // -------------------------- helpers -------------------------- //
841
+
842
+ var getComputedStyle = window.getComputedStyle;
843
+ var getStyle = getComputedStyle ?
844
+ function( elem ) {
845
+ return getComputedStyle( elem, null );
846
+ } :
847
+ function( elem ) {
848
+ return elem.currentStyle;
849
+ };
850
+
851
+ // get a number from a string, not a percentage
852
+ function getStyleSize( value ) {
853
+ var num = parseFloat( value );
854
+ // not a percent like '100%', and a number
855
+ var isValid = value.indexOf('%') === -1 && !isNaN( num );
856
+ return isValid && num;
857
+ }
858
+
859
+ // -------------------------- measurements -------------------------- //
860
+
861
+ var measurements = [
862
+ 'paddingLeft',
863
+ 'paddingRight',
864
+ 'paddingTop',
865
+ 'paddingBottom',
866
+ 'marginLeft',
867
+ 'marginRight',
868
+ 'marginTop',
869
+ 'marginBottom',
870
+ 'borderLeftWidth',
871
+ 'borderRightWidth',
872
+ 'borderTopWidth',
873
+ 'borderBottomWidth'
874
+ ];
875
+
876
+ function getZeroSize() {
877
+ var size = {
878
+ width: 0,
879
+ height: 0,
880
+ innerWidth: 0,
881
+ innerHeight: 0,
882
+ outerWidth: 0,
883
+ outerHeight: 0
884
+ };
885
+ for ( var i=0, len = measurements.length; i < len; i++ ) {
886
+ var measurement = measurements[i];
887
+ size[ measurement ] = 0;
888
+ }
889
+ return size;
890
+ }
891
+
892
+
893
+
894
+ function defineGetSize( getStyleProperty ) {
895
+
896
+ // -------------------------- box sizing -------------------------- //
897
+
898
+ var boxSizingProp = getStyleProperty('boxSizing');
899
+ var isBoxSizeOuter;
900
+
901
+ /**
902
+ * WebKit measures the outer-width on style.width on border-box elems
903
+ * IE & Firefox measures the inner-width
904
+ */
905
+ ( function() {
906
+ if ( !boxSizingProp ) {
907
+ return;
908
+ }
909
+
910
+ var div = document.createElement('div');
911
+ div.style.width = '200px';
912
+ div.style.padding = '1px 2px 3px 4px';
913
+ div.style.borderStyle = 'solid';
914
+ div.style.borderWidth = '1px 2px 3px 4px';
915
+ div.style[ boxSizingProp ] = 'border-box';
916
+
917
+ var body = document.body || document.documentElement;
918
+ body.appendChild( div );
919
+ var style = getStyle( div );
920
+
921
+ isBoxSizeOuter = getStyleSize( style.width ) === 200;
922
+ body.removeChild( div );
923
+ })();
924
+
925
+
926
+ // -------------------------- getSize -------------------------- //
927
+
928
+ function getSize( elem ) {
929
+ // use querySeletor if elem is string
930
+ if ( typeof elem === 'string' ) {
931
+ elem = document.querySelector( elem );
932
+ }
933
+
934
+ // do not proceed on non-objects
935
+ if ( !elem || typeof elem !== 'object' || !elem.nodeType ) {
936
+ return;
937
+ }
938
+
939
+ var style = getStyle( elem );
940
+
941
+ // if hidden, everything is 0
942
+ if ( style.display === 'none' ) {
943
+ return getZeroSize();
944
+ }
945
+
946
+ var size = {};
947
+ size.width = elem.offsetWidth;
948
+ size.height = elem.offsetHeight;
949
+
950
+ var isBorderBox = size.isBorderBox = !!( boxSizingProp &&
951
+ style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' );
952
+
953
+ // get all measurements
954
+ for ( var i=0, len = measurements.length; i < len; i++ ) {
955
+ var measurement = measurements[i];
956
+ var value = style[ measurement ];
957
+ value = mungeNonPixel( elem, value );
958
+ var num = parseFloat( value );
959
+ // any 'auto', 'medium' value will be 0
960
+ size[ measurement ] = !isNaN( num ) ? num : 0;
961
+ }
962
+
963
+ var paddingWidth = size.paddingLeft + size.paddingRight;
964
+ var paddingHeight = size.paddingTop + size.paddingBottom;
965
+ var marginWidth = size.marginLeft + size.marginRight;
966
+ var marginHeight = size.marginTop + size.marginBottom;
967
+ var borderWidth = size.borderLeftWidth + size.borderRightWidth;
968
+ var borderHeight = size.borderTopWidth + size.borderBottomWidth;
969
+
970
+ var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
971
+
972
+ // overwrite width and height if we can get it from style
973
+ var styleWidth = getStyleSize( style.width );
974
+ if ( styleWidth !== false ) {
975
+ size.width = styleWidth +
976
+ // add padding and border unless it's already including it
977
+ ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
978
+ }
979
+
980
+ var styleHeight = getStyleSize( style.height );
981
+ if ( styleHeight !== false ) {
982
+ size.height = styleHeight +
983
+ // add padding and border unless it's already including it
984
+ ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
985
+ }
986
+
987
+ size.innerWidth = size.width - ( paddingWidth + borderWidth );
988
+ size.innerHeight = size.height - ( paddingHeight + borderHeight );
989
+
990
+ size.outerWidth = size.width + marginWidth;
991
+ size.outerHeight = size.height + marginHeight;
992
+
993
+ return size;
994
+ }
995
+
996
+ // IE8 returns percent values, not pixels
997
+ // taken from jQuery's curCSS
998
+ function mungeNonPixel( elem, value ) {
999
+ // IE8 and has percent value
1000
+ if ( getComputedStyle || value.indexOf('%') === -1 ) {
1001
+ return value;
1002
+ }
1003
+ var style = elem.style;
1004
+ // Remember the original values
1005
+ var left = style.left;
1006
+ var rs = elem.runtimeStyle;
1007
+ var rsLeft = rs && rs.left;
1008
+
1009
+ // Put in the new values to get a computed value out
1010
+ if ( rsLeft ) {
1011
+ rs.left = elem.currentStyle.left;
1012
+ }
1013
+ style.left = value;
1014
+ value = style.pixelLeft;
1015
+
1016
+ // Revert the changed values
1017
+ style.left = left;
1018
+ if ( rsLeft ) {
1019
+ rs.left = rsLeft;
1020
+ }
1021
+
1022
+ return value;
1023
+ }
1024
+
1025
+ return getSize;
1026
+
1027
+ }
1028
+
1029
+ // transport
1030
+ if ( typeof define === 'function' && define.amd ) {
1031
+ // AMD for RequireJS
1032
+ define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize );
1033
+ } else if ( typeof exports === 'object' ) {
1034
+ // CommonJS for Component
1035
+ module.exports = defineGetSize( require('get-style-property') );
1036
+ } else {
1037
+ // browser global
1038
+ window.getSize = defineGetSize( window.getStyleProperty );
1039
+ }
1040
+
1041
+ })( window );
1042
+
1043
+ /**
1044
+ * matchesSelector helper v1.0.1
1045
+ *
1046
+ * @name matchesSelector
1047
+ * @param {Element} elem
1048
+ * @param {String} selector
1049
+ */
1050
+
1051
+ /*jshint browser: true, strict: true, undef: true, unused: true */
1052
+ /*global define: false */
1053
+
1054
+ ( function( global, ElemProto ) {
1055
+
1056
+
1057
+
1058
+ var matchesMethod = ( function() {
1059
+ // check un-prefixed
1060
+ if ( ElemProto.matchesSelector ) {
1061
+ return 'matchesSelector';
1062
+ }
1063
+ // check vendor prefixes
1064
+ var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
1065
+
1066
+ for ( var i=0, len = prefixes.length; i < len; i++ ) {
1067
+ var prefix = prefixes[i];
1068
+ var method = prefix + 'MatchesSelector';
1069
+ if ( ElemProto[ method ] ) {
1070
+ return method;
1071
+ }
1072
+ }
1073
+ })();
1074
+
1075
+ // ----- match ----- //
1076
+
1077
+ function match( elem, selector ) {
1078
+ return elem[ matchesMethod ]( selector );
1079
+ }
1080
+
1081
+ // ----- appendToFragment ----- //
1082
+
1083
+ function checkParent( elem ) {
1084
+ // not needed if already has parent
1085
+ if ( elem.parentNode ) {
1086
+ return;
1087
+ }
1088
+ var fragment = document.createDocumentFragment();
1089
+ fragment.appendChild( elem );
1090
+ }
1091
+
1092
+ // ----- query ----- //
1093
+
1094
+ // fall back to using QSA
1095
+ // thx @jonathantneal https://gist.github.com/3062955
1096
+ function query( elem, selector ) {
1097
+ // append to fragment if no parent
1098
+ checkParent( elem );
1099
+
1100
+ // match elem with all selected elems of parent
1101
+ var elems = elem.parentNode.querySelectorAll( selector );
1102
+ for ( var i=0, len = elems.length; i < len; i++ ) {
1103
+ // return true if match
1104
+ if ( elems[i] === elem ) {
1105
+ return true;
1106
+ }
1107
+ }
1108
+ // otherwise return false
1109
+ return false;
1110
+ }
1111
+
1112
+ // ----- matchChild ----- //
1113
+
1114
+ function matchChild( elem, selector ) {
1115
+ checkParent( elem );
1116
+ return match( elem, selector );
1117
+ }
1118
+
1119
+ // ----- matchesSelector ----- //
1120
+
1121
+ var matchesSelector;
1122
+
1123
+ if ( matchesMethod ) {
1124
+ // IE9 supports matchesSelector, but doesn't work on orphaned elems
1125
+ // check for that
1126
+ var div = document.createElement('div');
1127
+ var supportsOrphans = match( div, 'div' );
1128
+ matchesSelector = supportsOrphans ? match : matchChild;
1129
+ } else {
1130
+ matchesSelector = query;
1131
+ }
1132
+
1133
+ // transport
1134
+ if ( typeof define === 'function' && define.amd ) {
1135
+ // AMD
1136
+ define( 'matches-selector/matches-selector',[],function() {
1137
+ return matchesSelector;
1138
+ });
1139
+ } else {
1140
+ // browser global
1141
+ window.matchesSelector = matchesSelector;
1142
+ }
1143
+
1144
+ })( this, Element.prototype );
1145
+
1146
+ /**
1147
+ * Outlayer Item
1148
+ */
1149
+
1150
+ ( function( window ) {
1151
+
1152
+
1153
+
1154
+ // ----- get style ----- //
1155
+
1156
+ var getComputedStyle = window.getComputedStyle;
1157
+ var getStyle = getComputedStyle ?
1158
+ function( elem ) {
1159
+ return getComputedStyle( elem, null );
1160
+ } :
1161
+ function( elem ) {
1162
+ return elem.currentStyle;
1163
+ };
1164
+
1165
+
1166
+ // extend objects
1167
+ function extend( a, b ) {
1168
+ for ( var prop in b ) {
1169
+ a[ prop ] = b[ prop ];
1170
+ }
1171
+ return a;
1172
+ }
1173
+
1174
+ function isEmptyObj( obj ) {
1175
+ for ( var prop in obj ) {
1176
+ return false;
1177
+ }
1178
+ prop = null;
1179
+ return true;
1180
+ }
1181
+
1182
+ // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
1183
+ function toDash( str ) {
1184
+ return str.replace( /([A-Z])/g, function( $1 ){
1185
+ return '-' + $1.toLowerCase();
1186
+ });
1187
+ }
1188
+
1189
+ // -------------------------- Outlayer definition -------------------------- //
1190
+
1191
+ function outlayerItemDefinition( EventEmitter, getSize, getStyleProperty ) {
1192
+
1193
+ // -------------------------- CSS3 support -------------------------- //
1194
+
1195
+ var transitionProperty = getStyleProperty('transition');
1196
+ var transformProperty = getStyleProperty('transform');
1197
+ var supportsCSS3 = transitionProperty && transformProperty;
1198
+ var is3d = !!getStyleProperty('perspective');
1199
+
1200
+ var transitionEndEvent = {
1201
+ WebkitTransition: 'webkitTransitionEnd',
1202
+ MozTransition: 'transitionend',
1203
+ OTransition: 'otransitionend',
1204
+ transition: 'transitionend'
1205
+ }[ transitionProperty ];
1206
+
1207
+ // properties that could have vendor prefix
1208
+ var prefixableProperties = [
1209
+ 'transform',
1210
+ 'transition',
1211
+ 'transitionDuration',
1212
+ 'transitionProperty'
1213
+ ];
1214
+
1215
+ // cache all vendor properties
1216
+ var vendorProperties = ( function() {
1217
+ var cache = {};
1218
+ for ( var i=0, len = prefixableProperties.length; i < len; i++ ) {
1219
+ var prop = prefixableProperties[i];
1220
+ var supportedProp = getStyleProperty( prop );
1221
+ if ( supportedProp && supportedProp !== prop ) {
1222
+ cache[ prop ] = supportedProp;
1223
+ }
1224
+ }
1225
+ return cache;
1226
+ })();
1227
+
1228
+ // -------------------------- Item -------------------------- //
1229
+
1230
+ function Item( element, layout ) {
1231
+ if ( !element ) {
1232
+ return;
1233
+ }
1234
+
1235
+ this.element = element;
1236
+ // parent layout class, i.e. Masonry, Isotope, or Packery
1237
+ this.layout = layout;
1238
+ this.position = {
1239
+ x: 0,
1240
+ y: 0
1241
+ };
1242
+
1243
+ this._create();
1244
+ }
1245
+
1246
+ // inherit EventEmitter
1247
+ extend( Item.prototype, EventEmitter.prototype );
1248
+
1249
+ Item.prototype._create = function() {
1250
+ // transition objects
1251
+ this._transn = {
1252
+ ingProperties: {},
1253
+ clean: {},
1254
+ onEnd: {}
1255
+ };
1256
+
1257
+ this.css({
1258
+ position: 'absolute'
1259
+ });
1260
+ };
1261
+
1262
+ // trigger specified handler for event type
1263
+ Item.prototype.handleEvent = function( event ) {
1264
+ var method = 'on' + event.type;
1265
+ if ( this[ method ] ) {
1266
+ this[ method ]( event );
1267
+ }
1268
+ };
1269
+
1270
+ Item.prototype.getSize = function() {
1271
+ this.size = getSize( this.element );
1272
+ };
1273
+
1274
+ /**
1275
+ * apply CSS styles to element
1276
+ * @param {Object} style
1277
+ */
1278
+ Item.prototype.css = function( style ) {
1279
+ var elemStyle = this.element.style;
1280
+
1281
+ for ( var prop in style ) {
1282
+ // use vendor property if available
1283
+ var supportedProp = vendorProperties[ prop ] || prop;
1284
+ elemStyle[ supportedProp ] = style[ prop ];
1285
+ }
1286
+ };
1287
+
1288
+ // measure position, and sets it
1289
+ Item.prototype.getPosition = function() {
1290
+ var style = getStyle( this.element );
1291
+ var layoutOptions = this.layout.options;
1292
+ var isOriginLeft = layoutOptions.isOriginLeft;
1293
+ var isOriginTop = layoutOptions.isOriginTop;
1294
+ var x = parseInt( style[ isOriginLeft ? 'left' : 'right' ], 10 );
1295
+ var y = parseInt( style[ isOriginTop ? 'top' : 'bottom' ], 10 );
1296
+
1297
+ // clean up 'auto' or other non-integer values
1298
+ x = isNaN( x ) ? 0 : x;
1299
+ y = isNaN( y ) ? 0 : y;
1300
+ // remove padding from measurement
1301
+ var layoutSize = this.layout.size;
1302
+ x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
1303
+ y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
1304
+
1305
+ this.position.x = x;
1306
+ this.position.y = y;
1307
+ };
1308
+
1309
+ // set settled position, apply padding
1310
+ Item.prototype.layoutPosition = function() {
1311
+ var layoutSize = this.layout.size;
1312
+ var layoutOptions = this.layout.options;
1313
+ var style = {};
1314
+
1315
+ if ( layoutOptions.isOriginLeft ) {
1316
+ style.left = ( this.position.x + layoutSize.paddingLeft ) + 'px';
1317
+ // reset other property
1318
+ style.right = '';
1319
+ } else {
1320
+ style.right = ( this.position.x + layoutSize.paddingRight ) + 'px';
1321
+ style.left = '';
1322
+ }
1323
+
1324
+ if ( layoutOptions.isOriginTop ) {
1325
+ style.top = ( this.position.y + layoutSize.paddingTop ) + 'px';
1326
+ style.bottom = '';
1327
+ } else {
1328
+ style.bottom = ( this.position.y + layoutSize.paddingBottom ) + 'px';
1329
+ style.top = '';
1330
+ }
1331
+
1332
+ this.css( style );
1333
+ this.emitEvent( 'layout', [ this ] );
1334
+ };
1335
+
1336
+
1337
+ // transform translate function
1338
+ var translate = is3d ?
1339
+ function( x, y ) {
1340
+ return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
1341
+ } :
1342
+ function( x, y ) {
1343
+ return 'translate(' + x + 'px, ' + y + 'px)';
1344
+ };
1345
+
1346
+
1347
+ Item.prototype._transitionTo = function( x, y ) {
1348
+ this.getPosition();
1349
+ // get current x & y from top/left
1350
+ var curX = this.position.x;
1351
+ var curY = this.position.y;
1352
+
1353
+ var compareX = parseInt( x, 10 );
1354
+ var compareY = parseInt( y, 10 );
1355
+ var didNotMove = compareX === this.position.x && compareY === this.position.y;
1356
+
1357
+ // save end position
1358
+ this.setPosition( x, y );
1359
+
1360
+ // if did not move and not transitioning, just go to layout
1361
+ if ( didNotMove && !this.isTransitioning ) {
1362
+ this.layoutPosition();
1363
+ return;
1364
+ }
1365
+
1366
+ var transX = x - curX;
1367
+ var transY = y - curY;
1368
+ var transitionStyle = {};
1369
+ // flip cooridinates if origin on right or bottom
1370
+ var layoutOptions = this.layout.options;
1371
+ transX = layoutOptions.isOriginLeft ? transX : -transX;
1372
+ transY = layoutOptions.isOriginTop ? transY : -transY;
1373
+ transitionStyle.transform = translate( transX, transY );
1374
+
1375
+ this.transition({
1376
+ to: transitionStyle,
1377
+ onTransitionEnd: {
1378
+ transform: this.layoutPosition
1379
+ },
1380
+ isCleaning: true
1381
+ });
1382
+ };
1383
+
1384
+ // non transition + transform support
1385
+ Item.prototype.goTo = function( x, y ) {
1386
+ this.setPosition( x, y );
1387
+ this.layoutPosition();
1388
+ };
1389
+
1390
+ // use transition and transforms if supported
1391
+ Item.prototype.moveTo = supportsCSS3 ?
1392
+ Item.prototype._transitionTo : Item.prototype.goTo;
1393
+
1394
+ Item.prototype.setPosition = function( x, y ) {
1395
+ this.position.x = parseInt( x, 10 );
1396
+ this.position.y = parseInt( y, 10 );
1397
+ };
1398
+
1399
+ // ----- transition ----- //
1400
+
1401
+ /**
1402
+ * @param {Object} style - CSS
1403
+ * @param {Function} onTransitionEnd
1404
+ */
1405
+
1406
+ // non transition, just trigger callback
1407
+ Item.prototype._nonTransition = function( args ) {
1408
+ this.css( args.to );
1409
+ if ( args.isCleaning ) {
1410
+ this._removeStyles( args.to );
1411
+ }
1412
+ for ( var prop in args.onTransitionEnd ) {
1413
+ args.onTransitionEnd[ prop ].call( this );
1414
+ }
1415
+ };
1416
+
1417
+ /**
1418
+ * proper transition
1419
+ * @param {Object} args - arguments
1420
+ * @param {Object} to - style to transition to
1421
+ * @param {Object} from - style to start transition from
1422
+ * @param {Boolean} isCleaning - removes transition styles after transition
1423
+ * @param {Function} onTransitionEnd - callback
1424
+ */
1425
+ Item.prototype._transition = function( args ) {
1426
+ // redirect to nonTransition if no transition duration
1427
+ if ( !parseFloat( this.layout.options.transitionDuration ) ) {
1428
+ this._nonTransition( args );
1429
+ return;
1430
+ }
1431
+
1432
+ var _transition = this._transn;
1433
+ // keep track of onTransitionEnd callback by css property
1434
+ for ( var prop in args.onTransitionEnd ) {
1435
+ _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
1436
+ }
1437
+ // keep track of properties that are transitioning
1438
+ for ( prop in args.to ) {
1439
+ _transition.ingProperties[ prop ] = true;
1440
+ // keep track of properties to clean up when transition is done
1441
+ if ( args.isCleaning ) {
1442
+ _transition.clean[ prop ] = true;
1443
+ }
1444
+ }
1445
+
1446
+ // set from styles
1447
+ if ( args.from ) {
1448
+ this.css( args.from );
1449
+ // force redraw. http://blog.alexmaccaw.com/css-transitions
1450
+ var h = this.element.offsetHeight;
1451
+ // hack for JSHint to hush about unused var
1452
+ h = null;
1453
+ }
1454
+ // enable transition
1455
+ this.enableTransition( args.to );
1456
+ // set styles that are transitioning
1457
+ this.css( args.to );
1458
+
1459
+ this.isTransitioning = true;
1460
+
1461
+ };
1462
+
1463
+ var itemTransitionProperties = transformProperty && ( toDash( transformProperty ) +
1464
+ ',opacity' );
1465
+
1466
+ Item.prototype.enableTransition = function(/* style */) {
1467
+ // only enable if not already transitioning
1468
+ // bug in IE10 were re-setting transition style will prevent
1469
+ // transitionend event from triggering
1470
+ if ( this.isTransitioning ) {
1471
+ return;
1472
+ }
1473
+
1474
+ // make transition: foo, bar, baz from style object
1475
+ // TODO uncomment this bit when IE10 bug is resolved
1476
+ // var transitionValue = [];
1477
+ // for ( var prop in style ) {
1478
+ // // dash-ify camelCased properties like WebkitTransition
1479
+ // transitionValue.push( toDash( prop ) );
1480
+ // }
1481
+ // enable transition styles
1482
+ // HACK always enable transform,opacity for IE10
1483
+ this.css({
1484
+ transitionProperty: itemTransitionProperties,
1485
+ transitionDuration: this.layout.options.transitionDuration
1486
+ });
1487
+ // listen for transition end event
1488
+ this.element.addEventListener( transitionEndEvent, this, false );
1489
+ };
1490
+
1491
+ Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ];
1492
+
1493
+ // ----- events ----- //
1494
+
1495
+ Item.prototype.onwebkitTransitionEnd = function( event ) {
1496
+ this.ontransitionend( event );
1497
+ };
1498
+
1499
+ Item.prototype.onotransitionend = function( event ) {
1500
+ this.ontransitionend( event );
1501
+ };
1502
+
1503
+ // properties that I munge to make my life easier
1504
+ var dashedVendorProperties = {
1505
+ '-webkit-transform': 'transform',
1506
+ '-moz-transform': 'transform',
1507
+ '-o-transform': 'transform'
1508
+ };
1509
+
1510
+ Item.prototype.ontransitionend = function( event ) {
1511
+ // disregard bubbled events from children
1512
+ if ( event.target !== this.element ) {
1513
+ return;
1514
+ }
1515
+ var _transition = this._transn;
1516
+ // get property name of transitioned property, convert to prefix-free
1517
+ var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
1518
+
1519
+ // remove property that has completed transitioning
1520
+ delete _transition.ingProperties[ propertyName ];
1521
+ // check if any properties are still transitioning
1522
+ if ( isEmptyObj( _transition.ingProperties ) ) {
1523
+ // all properties have completed transitioning
1524
+ this.disableTransition();
1525
+ }
1526
+ // clean style
1527
+ if ( propertyName in _transition.clean ) {
1528
+ // clean up style
1529
+ this.element.style[ event.propertyName ] = '';
1530
+ delete _transition.clean[ propertyName ];
1531
+ }
1532
+ // trigger onTransitionEnd callback
1533
+ if ( propertyName in _transition.onEnd ) {
1534
+ var onTransitionEnd = _transition.onEnd[ propertyName ];
1535
+ onTransitionEnd.call( this );
1536
+ delete _transition.onEnd[ propertyName ];
1537
+ }
1538
+
1539
+ this.emitEvent( 'transitionEnd', [ this ] );
1540
+ };
1541
+
1542
+ Item.prototype.disableTransition = function() {
1543
+ this.removeTransitionStyles();
1544
+ this.element.removeEventListener( transitionEndEvent, this, false );
1545
+ this.isTransitioning = false;
1546
+ };
1547
+
1548
+ /**
1549
+ * removes style property from element
1550
+ * @param {Object} style
1551
+ **/
1552
+ Item.prototype._removeStyles = function( style ) {
1553
+ // clean up transition styles
1554
+ var cleanStyle = {};
1555
+ for ( var prop in style ) {
1556
+ cleanStyle[ prop ] = '';
1557
+ }
1558
+ this.css( cleanStyle );
1559
+ };
1560
+
1561
+ var cleanTransitionStyle = {
1562
+ transitionProperty: '',
1563
+ transitionDuration: ''
1564
+ };
1565
+
1566
+ Item.prototype.removeTransitionStyles = function() {
1567
+ // remove transition
1568
+ this.css( cleanTransitionStyle );
1569
+ };
1570
+
1571
+ // ----- show/hide/remove ----- //
1572
+
1573
+ // remove element from DOM
1574
+ Item.prototype.removeElem = function() {
1575
+ this.element.parentNode.removeChild( this.element );
1576
+ this.emitEvent( 'remove', [ this ] );
1577
+ };
1578
+
1579
+ Item.prototype.remove = function() {
1580
+ // just remove element if no transition support or no transition
1581
+ if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
1582
+ this.removeElem();
1583
+ return;
1584
+ }
1585
+
1586
+ // start transition
1587
+ var _this = this;
1588
+ this.on( 'transitionEnd', function() {
1589
+ _this.removeElem();
1590
+ return true; // bind once
1591
+ });
1592
+ this.hide();
1593
+ };
1594
+
1595
+ Item.prototype.reveal = function() {
1596
+ delete this.isHidden;
1597
+ // remove display: none
1598
+ this.css({ display: '' });
1599
+
1600
+ var options = this.layout.options;
1601
+ this.transition({
1602
+ from: options.hiddenStyle,
1603
+ to: options.visibleStyle,
1604
+ isCleaning: true
1605
+ });
1606
+ };
1607
+
1608
+ Item.prototype.hide = function() {
1609
+ // set flag
1610
+ this.isHidden = true;
1611
+ // remove display: none
1612
+ this.css({ display: '' });
1613
+
1614
+ var options = this.layout.options;
1615
+ this.transition({
1616
+ from: options.visibleStyle,
1617
+ to: options.hiddenStyle,
1618
+ // keep hidden stuff hidden
1619
+ isCleaning: true,
1620
+ onTransitionEnd: {
1621
+ opacity: function() {
1622
+ // check if still hidden
1623
+ // during transition, item may have been un-hidden
1624
+ if ( this.isHidden ) {
1625
+ this.css({ display: 'none' });
1626
+ }
1627
+ }
1628
+ }
1629
+ });
1630
+ };
1631
+
1632
+ Item.prototype.destroy = function() {
1633
+ this.css({
1634
+ position: '',
1635
+ left: '',
1636
+ right: '',
1637
+ top: '',
1638
+ bottom: '',
1639
+ transition: '',
1640
+ transform: ''
1641
+ });
1642
+ };
1643
+
1644
+ return Item;
1645
+
1646
+ }
1647
+
1648
+ // -------------------------- transport -------------------------- //
1649
+
1650
+ if ( typeof define === 'function' && define.amd ) {
1651
+ // AMD
1652
+ define( 'outlayer/item',[
1653
+ 'eventEmitter/EventEmitter',
1654
+ 'get-size/get-size',
1655
+ 'get-style-property/get-style-property'
1656
+ ],
1657
+ outlayerItemDefinition );
1658
+ } else {
1659
+ // browser global
1660
+ window.Outlayer = {};
1661
+ window.Outlayer.Item = outlayerItemDefinition(
1662
+ window.EventEmitter,
1663
+ window.getSize,
1664
+ window.getStyleProperty
1665
+ );
1666
+ }
1667
+
1668
+ })( window );
1669
+
1670
+ /*!
1671
+ * Outlayer v1.2.0
1672
+ * the brains and guts of a layout library
1673
+ * MIT license
1674
+ */
1675
+
1676
+ ( function( window ) {
1677
+
1678
+
1679
+
1680
+ // ----- vars ----- //
1681
+
1682
+ var document = window.document;
1683
+ var console = window.console;
1684
+ var jQuery = window.jQuery;
1685
+
1686
+ var noop = function() {};
1687
+
1688
+ // -------------------------- helpers -------------------------- //
1689
+
1690
+ // extend objects
1691
+ function extend( a, b ) {
1692
+ for ( var prop in b ) {
1693
+ a[ prop ] = b[ prop ];
1694
+ }
1695
+ return a;
1696
+ }
1697
+
1698
+
1699
+ var objToString = Object.prototype.toString;
1700
+ function isArray( obj ) {
1701
+ return objToString.call( obj ) === '[object Array]';
1702
+ }
1703
+
1704
+ // turn element or nodeList into an array
1705
+ function makeArray( obj ) {
1706
+ var ary = [];
1707
+ if ( isArray( obj ) ) {
1708
+ // use object if already an array
1709
+ ary = obj;
1710
+ } else if ( obj && typeof obj.length === 'number' ) {
1711
+ // convert nodeList to array
1712
+ for ( var i=0, len = obj.length; i < len; i++ ) {
1713
+ ary.push( obj[i] );
1714
+ }
1715
+ } else {
1716
+ // array of single index
1717
+ ary.push( obj );
1718
+ }
1719
+ return ary;
1720
+ }
1721
+
1722
+ // http://stackoverflow.com/a/384380/182183
1723
+ var isElement = ( typeof HTMLElement === 'object' ) ?
1724
+ function isElementDOM2( obj ) {
1725
+ return obj instanceof HTMLElement;
1726
+ } :
1727
+ function isElementQuirky( obj ) {
1728
+ return obj && typeof obj === 'object' &&
1729
+ obj.nodeType === 1 && typeof obj.nodeName === 'string';
1730
+ };
1731
+
1732
+ // index of helper cause IE8
1733
+ var indexOf = Array.prototype.indexOf ? function( ary, obj ) {
1734
+ return ary.indexOf( obj );
1735
+ } : function( ary, obj ) {
1736
+ for ( var i=0, len = ary.length; i < len; i++ ) {
1737
+ if ( ary[i] === obj ) {
1738
+ return i;
1739
+ }
1740
+ }
1741
+ return -1;
1742
+ };
1743
+
1744
+ function removeFrom( obj, ary ) {
1745
+ var index = indexOf( ary, obj );
1746
+ if ( index !== -1 ) {
1747
+ ary.splice( index, 1 );
1748
+ }
1749
+ }
1750
+
1751
+ // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
1752
+ function toDashed( str ) {
1753
+ return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
1754
+ return $1 + '-' + $2;
1755
+ }).toLowerCase();
1756
+ }
1757
+
1758
+
1759
+ function outlayerDefinition( eventie, docReady, EventEmitter, getSize, matchesSelector, Item ) {
1760
+
1761
+ // -------------------------- Outlayer -------------------------- //
1762
+
1763
+ // globally unique identifiers
1764
+ var GUID = 0;
1765
+ // internal store of all Outlayer intances
1766
+ var instances = {};
1767
+
1768
+
1769
+ /**
1770
+ * @param {Element, String} element
1771
+ * @param {Object} options
1772
+ * @constructor
1773
+ */
1774
+ function Outlayer( element, options ) {
1775
+ // use element as selector string
1776
+ if ( typeof element === 'string' ) {
1777
+ element = document.querySelector( element );
1778
+ }
1779
+
1780
+ // bail out if not proper element
1781
+ if ( !element || !isElement( element ) ) {
1782
+ if ( console ) {
1783
+ console.error( 'Bad ' + this.constructor.namespace + ' element: ' + element );
1784
+ }
1785
+ return;
1786
+ }
1787
+
1788
+ this.element = element;
1789
+
1790
+ // options
1791
+ this.options = extend( {}, this.constructor.defaults );
1792
+ this.option( options );
1793
+
1794
+ // add id for Outlayer.getFromElement
1795
+ var id = ++GUID;
1796
+ this.element.outlayerGUID = id; // expando
1797
+ instances[ id ] = this; // associate via id
1798
+
1799
+ // kick it off
1800
+ this._create();
1801
+
1802
+ if ( this.options.isInitLayout ) {
1803
+ this.layout();
1804
+ }
1805
+ }
1806
+
1807
+ // settings are for internal use only
1808
+ Outlayer.namespace = 'outlayer';
1809
+ Outlayer.Item = Item;
1810
+
1811
+ // default options
1812
+ Outlayer.defaults = {
1813
+ containerStyle: {
1814
+ position: 'relative'
1815
+ },
1816
+ isInitLayout: true,
1817
+ isOriginLeft: true,
1818
+ isOriginTop: true,
1819
+ isResizeBound: true,
1820
+ isResizingContainer: true,
1821
+ // item options
1822
+ transitionDuration: '0.4s',
1823
+ hiddenStyle: {
1824
+ opacity: 0,
1825
+ transform: 'scale(0.001)'
1826
+ },
1827
+ visibleStyle: {
1828
+ opacity: 1,
1829
+ transform: 'scale(1)'
1830
+ }
1831
+ };
1832
+
1833
+ // inherit EventEmitter
1834
+ extend( Outlayer.prototype, EventEmitter.prototype );
1835
+
1836
+ /**
1837
+ * set options
1838
+ * @param {Object} opts
1839
+ */
1840
+ Outlayer.prototype.option = function( opts ) {
1841
+ extend( this.options, opts );
1842
+ };
1843
+
1844
+ Outlayer.prototype._create = function() {
1845
+ // get items from children
1846
+ this.reloadItems();
1847
+ // elements that affect layout, but are not laid out
1848
+ this.stamps = [];
1849
+ this.stamp( this.options.stamp );
1850
+ // set container style
1851
+ extend( this.element.style, this.options.containerStyle );
1852
+
1853
+ // bind resize method
1854
+ if ( this.options.isResizeBound ) {
1855
+ this.bindResize();
1856
+ }
1857
+ };
1858
+
1859
+ // goes through all children again and gets bricks in proper order
1860
+ Outlayer.prototype.reloadItems = function() {
1861
+ // collection of item elements
1862
+ this.items = this._itemize( this.element.children );
1863
+ };
1864
+
1865
+
1866
+ /**
1867
+ * turn elements into Outlayer.Items to be used in layout
1868
+ * @param {Array or NodeList or HTMLElement} elems
1869
+ * @returns {Array} items - collection of new Outlayer Items
1870
+ */
1871
+ Outlayer.prototype._itemize = function( elems ) {
1872
+
1873
+ var itemElems = this._filterFindItemElements( elems );
1874
+ var Item = this.constructor.Item;
1875
+
1876
+ // create new Outlayer Items for collection
1877
+ var items = [];
1878
+ for ( var i=0, len = itemElems.length; i < len; i++ ) {
1879
+ var elem = itemElems[i];
1880
+ var item = new Item( elem, this );
1881
+ items.push( item );
1882
+ }
1883
+
1884
+ return items;
1885
+ };
1886
+
1887
+ /**
1888
+ * get item elements to be used in layout
1889
+ * @param {Array or NodeList or HTMLElement} elems
1890
+ * @returns {Array} items - item elements
1891
+ */
1892
+ Outlayer.prototype._filterFindItemElements = function( elems ) {
1893
+ // make array of elems
1894
+ elems = makeArray( elems );
1895
+ var itemSelector = this.options.itemSelector;
1896
+ var itemElems = [];
1897
+
1898
+ for ( var i=0, len = elems.length; i < len; i++ ) {
1899
+ var elem = elems[i];
1900
+ // check that elem is an actual element
1901
+ if ( !isElement( elem ) ) {
1902
+ continue;
1903
+ }
1904
+ // filter & find items if we have an item selector
1905
+ if ( itemSelector ) {
1906
+ // filter siblings
1907
+ if ( matchesSelector( elem, itemSelector ) ) {
1908
+ itemElems.push( elem );
1909
+ }
1910
+ // find children
1911
+ var childElems = elem.querySelectorAll( itemSelector );
1912
+ // concat childElems to filterFound array
1913
+ for ( var j=0, jLen = childElems.length; j < jLen; j++ ) {
1914
+ itemElems.push( childElems[j] );
1915
+ }
1916
+ } else {
1917
+ itemElems.push( elem );
1918
+ }
1919
+ }
1920
+
1921
+ return itemElems;
1922
+ };
1923
+
1924
+ /**
1925
+ * getter method for getting item elements
1926
+ * @returns {Array} elems - collection of item elements
1927
+ */
1928
+ Outlayer.prototype.getItemElements = function() {
1929
+ var elems = [];
1930
+ for ( var i=0, len = this.items.length; i < len; i++ ) {
1931
+ elems.push( this.items[i].element );
1932
+ }
1933
+ return elems;
1934
+ };
1935
+
1936
+ // ----- init & layout ----- //
1937
+
1938
+ /**
1939
+ * lays out all items
1940
+ */
1941
+ Outlayer.prototype.layout = function() {
1942
+ this._resetLayout();
1943
+ this._manageStamps();
1944
+
1945
+ // don't animate first layout
1946
+ var isInstant = this.options.isLayoutInstant !== undefined ?
1947
+ this.options.isLayoutInstant : !this._isLayoutInited;
1948
+ this.layoutItems( this.items, isInstant );
1949
+
1950
+ // flag for initalized
1951
+ this._isLayoutInited = true;
1952
+ };
1953
+
1954
+ // _init is alias for layout
1955
+ Outlayer.prototype._init = Outlayer.prototype.layout;
1956
+
1957
+ /**
1958
+ * logic before any new layout
1959
+ */
1960
+ Outlayer.prototype._resetLayout = function() {
1961
+ this.getSize();
1962
+ };
1963
+
1964
+
1965
+ Outlayer.prototype.getSize = function() {
1966
+ this.size = getSize( this.element );
1967
+ };
1968
+
1969
+ /**
1970
+ * get measurement from option, for columnWidth, rowHeight, gutter
1971
+ * if option is String -> get element from selector string, & get size of element
1972
+ * if option is Element -> get size of element
1973
+ * else use option as a number
1974
+ *
1975
+ * @param {String} measurement
1976
+ * @param {String} size - width or height
1977
+ * @private
1978
+ */
1979
+ Outlayer.prototype._getMeasurement = function( measurement, size ) {
1980
+ var option = this.options[ measurement ];
1981
+ var elem;
1982
+ if ( !option ) {
1983
+ // default to 0
1984
+ this[ measurement ] = 0;
1985
+ } else {
1986
+ // use option as an element
1987
+ if ( typeof option === 'string' ) {
1988
+ elem = this.element.querySelector( option );
1989
+ } else if ( isElement( option ) ) {
1990
+ elem = option;
1991
+ }
1992
+ // use size of element, if element
1993
+ this[ measurement ] = elem ? getSize( elem )[ size ] : option;
1994
+ }
1995
+ };
1996
+
1997
+ /**
1998
+ * layout a collection of item elements
1999
+ * @api public
2000
+ */
2001
+ Outlayer.prototype.layoutItems = function( items, isInstant ) {
2002
+ items = this._getItemsForLayout( items );
2003
+
2004
+ this._layoutItems( items, isInstant );
2005
+
2006
+ this._postLayout();
2007
+ };
2008
+
2009
+ /**
2010
+ * get the items to be laid out
2011
+ * you may want to skip over some items
2012
+ * @param {Array} items
2013
+ * @returns {Array} items
2014
+ */
2015
+ Outlayer.prototype._getItemsForLayout = function( items ) {
2016
+ var layoutItems = [];
2017
+ for ( var i=0, len = items.length; i < len; i++ ) {
2018
+ var item = items[i];
2019
+ if ( !item.isIgnored ) {
2020
+ layoutItems.push( item );
2021
+ }
2022
+ }
2023
+ return layoutItems;
2024
+ };
2025
+
2026
+ /**
2027
+ * layout items
2028
+ * @param {Array} items
2029
+ * @param {Boolean} isInstant
2030
+ */
2031
+ Outlayer.prototype._layoutItems = function( items, isInstant ) {
2032
+ var _this = this;
2033
+ function onItemsLayout() {
2034
+ _this.emitEvent( 'layoutComplete', [ _this, items ] );
2035
+ }
2036
+
2037
+ if ( !items || !items.length ) {
2038
+ // no items, emit event with empty array
2039
+ onItemsLayout();
2040
+ return;
2041
+ }
2042
+
2043
+ // emit layoutComplete when done
2044
+ this._itemsOn( items, 'layout', onItemsLayout );
2045
+
2046
+ var queue = [];
2047
+
2048
+ for ( var i=0, len = items.length; i < len; i++ ) {
2049
+ var item = items[i];
2050
+ // get x/y object from method
2051
+ var position = this._getItemLayoutPosition( item );
2052
+ // enqueue
2053
+ position.item = item;
2054
+ position.isInstant = isInstant || item.isLayoutInstant;
2055
+ queue.push( position );
2056
+ }
2057
+
2058
+ this._processLayoutQueue( queue );
2059
+ };
2060
+
2061
+ /**
2062
+ * get item layout position
2063
+ * @param {Outlayer.Item} item
2064
+ * @returns {Object} x and y position
2065
+ */
2066
+ Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) {
2067
+ return {
2068
+ x: 0,
2069
+ y: 0
2070
+ };
2071
+ };
2072
+
2073
+ /**
2074
+ * iterate over array and position each item
2075
+ * Reason being - separating this logic prevents 'layout invalidation'
2076
+ * thx @paul_irish
2077
+ * @param {Array} queue
2078
+ */
2079
+ Outlayer.prototype._processLayoutQueue = function( queue ) {
2080
+ for ( var i=0, len = queue.length; i < len; i++ ) {
2081
+ var obj = queue[i];
2082
+ this._positionItem( obj.item, obj.x, obj.y, obj.isInstant );
2083
+ }
2084
+ };
2085
+
2086
+ /**
2087
+ * Sets position of item in DOM
2088
+ * @param {Outlayer.Item} item
2089
+ * @param {Number} x - horizontal position
2090
+ * @param {Number} y - vertical position
2091
+ * @param {Boolean} isInstant - disables transitions
2092
+ */
2093
+ Outlayer.prototype._positionItem = function( item, x, y, isInstant ) {
2094
+ if ( isInstant ) {
2095
+ // if not transition, just set CSS
2096
+ item.goTo( x, y );
2097
+ } else {
2098
+ item.moveTo( x, y );
2099
+ }
2100
+ };
2101
+
2102
+ /**
2103
+ * Any logic you want to do after each layout,
2104
+ * i.e. size the container
2105
+ */
2106
+ Outlayer.prototype._postLayout = function() {
2107
+ this.resizeContainer();
2108
+ };
2109
+
2110
+ Outlayer.prototype.resizeContainer = function() {
2111
+ if ( !this.options.isResizingContainer ) {
2112
+ return;
2113
+ }
2114
+ var size = this._getContainerSize();
2115
+ if ( size ) {
2116
+ this._setContainerMeasure( size.width, true );
2117
+ this._setContainerMeasure( size.height, false );
2118
+ }
2119
+ };
2120
+
2121
+ /**
2122
+ * Sets width or height of container if returned
2123
+ * @returns {Object} size
2124
+ * @param {Number} width
2125
+ * @param {Number} height
2126
+ */
2127
+ Outlayer.prototype._getContainerSize = noop;
2128
+
2129
+ /**
2130
+ * @param {Number} measure - size of width or height
2131
+ * @param {Boolean} isWidth
2132
+ */
2133
+ Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) {
2134
+ if ( measure === undefined ) {
2135
+ return;
2136
+ }
2137
+
2138
+ var elemSize = this.size;
2139
+ // add padding and border width if border box
2140
+ if ( elemSize.isBorderBox ) {
2141
+ measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
2142
+ elemSize.borderLeftWidth + elemSize.borderRightWidth :
2143
+ elemSize.paddingBottom + elemSize.paddingTop +
2144
+ elemSize.borderTopWidth + elemSize.borderBottomWidth;
2145
+ }
2146
+
2147
+ measure = Math.max( measure, 0 );
2148
+ this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
2149
+ };
2150
+
2151
+ /**
2152
+ * trigger a callback for a collection of items events
2153
+ * @param {Array} items - Outlayer.Items
2154
+ * @param {String} eventName
2155
+ * @param {Function} callback
2156
+ */
2157
+ Outlayer.prototype._itemsOn = function( items, eventName, callback ) {
2158
+ var doneCount = 0;
2159
+ var count = items.length;
2160
+ // event callback
2161
+ var _this = this;
2162
+ function tick() {
2163
+ doneCount++;
2164
+ if ( doneCount === count ) {
2165
+ callback.call( _this );
2166
+ }
2167
+ return true; // bind once
2168
+ }
2169
+ // bind callback
2170
+ for ( var i=0, len = items.length; i < len; i++ ) {
2171
+ var item = items[i];
2172
+ item.on( eventName, tick );
2173
+ }
2174
+ };
2175
+
2176
+ // -------------------------- ignore & stamps -------------------------- //
2177
+
2178
+
2179
+ /**
2180
+ * keep item in collection, but do not lay it out
2181
+ * ignored items do not get skipped in layout
2182
+ * @param {Element} elem
2183
+ */
2184
+ Outlayer.prototype.ignore = function( elem ) {
2185
+ var item = this.getItem( elem );
2186
+ if ( item ) {
2187
+ item.isIgnored = true;
2188
+ }
2189
+ };
2190
+
2191
+ /**
2192
+ * return item to layout collection
2193
+ * @param {Element} elem
2194
+ */
2195
+ Outlayer.prototype.unignore = function( elem ) {
2196
+ var item = this.getItem( elem );
2197
+ if ( item ) {
2198
+ delete item.isIgnored;
2199
+ }
2200
+ };
2201
+
2202
+ /**
2203
+ * adds elements to stamps
2204
+ * @param {NodeList, Array, Element, or String} elems
2205
+ */
2206
+ Outlayer.prototype.stamp = function( elems ) {
2207
+ elems = this._find( elems );
2208
+ if ( !elems ) {
2209
+ return;
2210
+ }
2211
+
2212
+ this.stamps = this.stamps.concat( elems );
2213
+ // ignore
2214
+ for ( var i=0, len = elems.length; i < len; i++ ) {
2215
+ var elem = elems[i];
2216
+ this.ignore( elem );
2217
+ }
2218
+ };
2219
+
2220
+ /**
2221
+ * removes elements to stamps
2222
+ * @param {NodeList, Array, or Element} elems
2223
+ */
2224
+ Outlayer.prototype.unstamp = function( elems ) {
2225
+ elems = this._find( elems );
2226
+ if ( !elems ){
2227
+ return;
2228
+ }
2229
+
2230
+ for ( var i=0, len = elems.length; i < len; i++ ) {
2231
+ var elem = elems[i];
2232
+ // filter out removed stamp elements
2233
+ removeFrom( elem, this.stamps );
2234
+ this.unignore( elem );
2235
+ }
2236
+
2237
+ };
2238
+
2239
+ /**
2240
+ * finds child elements
2241
+ * @param {NodeList, Array, Element, or String} elems
2242
+ * @returns {Array} elems
2243
+ */
2244
+ Outlayer.prototype._find = function( elems ) {
2245
+ if ( !elems ) {
2246
+ return;
2247
+ }
2248
+ // if string, use argument as selector string
2249
+ if ( typeof elems === 'string' ) {
2250
+ elems = this.element.querySelectorAll( elems );
2251
+ }
2252
+ elems = makeArray( elems );
2253
+ return elems;
2254
+ };
2255
+
2256
+ Outlayer.prototype._manageStamps = function() {
2257
+ if ( !this.stamps || !this.stamps.length ) {
2258
+ return;
2259
+ }
2260
+
2261
+ this._getBoundingRect();
2262
+
2263
+ for ( var i=0, len = this.stamps.length; i < len; i++ ) {
2264
+ var stamp = this.stamps[i];
2265
+ this._manageStamp( stamp );
2266
+ }
2267
+ };
2268
+
2269
+ // update boundingLeft / Top
2270
+ Outlayer.prototype._getBoundingRect = function() {
2271
+ // get bounding rect for container element
2272
+ var boundingRect = this.element.getBoundingClientRect();
2273
+ var size = this.size;
2274
+ this._boundingRect = {
2275
+ left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
2276
+ top: boundingRect.top + size.paddingTop + size.borderTopWidth,
2277
+ right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
2278
+ bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
2279
+ };
2280
+ };
2281
+
2282
+ /**
2283
+ * @param {Element} stamp
2284
+ **/
2285
+ Outlayer.prototype._manageStamp = noop;
2286
+
2287
+ /**
2288
+ * get x/y position of element relative to container element
2289
+ * @param {Element} elem
2290
+ * @returns {Object} offset - has left, top, right, bottom
2291
+ */
2292
+ Outlayer.prototype._getElementOffset = function( elem ) {
2293
+ var boundingRect = elem.getBoundingClientRect();
2294
+ var thisRect = this._boundingRect;
2295
+ var size = getSize( elem );
2296
+ var offset = {
2297
+ left: boundingRect.left - thisRect.left - size.marginLeft,
2298
+ top: boundingRect.top - thisRect.top - size.marginTop,
2299
+ right: thisRect.right - boundingRect.right - size.marginRight,
2300
+ bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
2301
+ };
2302
+ return offset;
2303
+ };
2304
+
2305
+ // -------------------------- resize -------------------------- //
2306
+
2307
+ // enable event handlers for listeners
2308
+ // i.e. resize -> onresize
2309
+ Outlayer.prototype.handleEvent = function( event ) {
2310
+ var method = 'on' + event.type;
2311
+ if ( this[ method ] ) {
2312
+ this[ method ]( event );
2313
+ }
2314
+ };
2315
+
2316
+ /**
2317
+ * Bind layout to window resizing
2318
+ */
2319
+ Outlayer.prototype.bindResize = function() {
2320
+ // bind just one listener
2321
+ if ( this.isResizeBound ) {
2322
+ return;
2323
+ }
2324
+ eventie.bind( window, 'resize', this );
2325
+ this.isResizeBound = true;
2326
+ };
2327
+
2328
+ /**
2329
+ * Unbind layout to window resizing
2330
+ */
2331
+ Outlayer.prototype.unbindResize = function() {
2332
+ if ( this.isResizeBound ) {
2333
+ eventie.unbind( window, 'resize', this );
2334
+ }
2335
+ this.isResizeBound = false;
2336
+ };
2337
+
2338
+ // original debounce by John Hann
2339
+ // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
2340
+
2341
+ // this fires every resize
2342
+ Outlayer.prototype.onresize = function() {
2343
+ if ( this.resizeTimeout ) {
2344
+ clearTimeout( this.resizeTimeout );
2345
+ }
2346
+
2347
+ var _this = this;
2348
+ function delayed() {
2349
+ _this.resize();
2350
+ delete _this.resizeTimeout;
2351
+ }
2352
+
2353
+ this.resizeTimeout = setTimeout( delayed, 100 );
2354
+ };
2355
+
2356
+ // debounced, layout on resize
2357
+ Outlayer.prototype.resize = function() {
2358
+ // don't trigger if size did not change
2359
+ // or if resize was unbound. See #9
2360
+
2361
+ if ( !this.isResizeBound || !this.needsResizeLayout() ) {
2362
+ return;
2363
+ }
2364
+
2365
+ this.layout();
2366
+ };
2367
+
2368
+ /**
2369
+ * check if layout is needed post layout
2370
+ * @returns Boolean
2371
+ */
2372
+ Outlayer.prototype.needsResizeLayout = function() {
2373
+ var size = getSize( this.element );
2374
+ // check that this.size and size are there
2375
+ // IE8 triggers resize on body size change, so they might not be
2376
+ var hasSizes = this.size && size;
2377
+ return hasSizes && size.innerWidth !== this.size.innerWidth;
2378
+ };
2379
+
2380
+ // -------------------------- methods -------------------------- //
2381
+
2382
+ /**
2383
+ * add items to Outlayer instance
2384
+ * @param {Array or NodeList or Element} elems
2385
+ * @returns {Array} items - Outlayer.Items
2386
+ **/
2387
+ Outlayer.prototype.addItems = function( elems ) {
2388
+ var items = this._itemize( elems );
2389
+ // add items to collection
2390
+ if ( items.length ) {
2391
+ this.items = this.items.concat( items );
2392
+ }
2393
+ return items;
2394
+ };
2395
+
2396
+ /**
2397
+ * Layout newly-appended item elements
2398
+ * @param {Array or NodeList or Element} elems
2399
+ */
2400
+ Outlayer.prototype.appended = function( elems ) {
2401
+ var items = this.addItems( elems );
2402
+ if ( !items.length ) {
2403
+ return;
2404
+ }
2405
+ // layout and reveal just the new items
2406
+ this.layoutItems( items, true );
2407
+ this.reveal( items );
2408
+ };
2409
+
2410
+ /**
2411
+ * Layout prepended elements
2412
+ * @param {Array or NodeList or Element} elems
2413
+ */
2414
+ Outlayer.prototype.prepended = function( elems ) {
2415
+ var items = this._itemize( elems );
2416
+ if ( !items.length ) {
2417
+ return;
2418
+ }
2419
+ // add items to beginning of collection
2420
+ var previousItems = this.items.slice(0);
2421
+ this.items = items.concat( previousItems );
2422
+ // start new layout
2423
+ this._resetLayout();
2424
+ this._manageStamps();
2425
+ // layout new stuff without transition
2426
+ this.layoutItems( items, true );
2427
+ this.reveal( items );
2428
+ // layout previous items
2429
+ this.layoutItems( previousItems );
2430
+ };
2431
+
2432
+ /**
2433
+ * reveal a collection of items
2434
+ * @param {Array of Outlayer.Items} items
2435
+ */
2436
+ Outlayer.prototype.reveal = function( items ) {
2437
+ var len = items && items.length;
2438
+ if ( !len ) {
2439
+ return;
2440
+ }
2441
+ for ( var i=0; i < len; i++ ) {
2442
+ var item = items[i];
2443
+ item.reveal();
2444
+ }
2445
+ };
2446
+
2447
+ /**
2448
+ * hide a collection of items
2449
+ * @param {Array of Outlayer.Items} items
2450
+ */
2451
+ Outlayer.prototype.hide = function( items ) {
2452
+ var len = items && items.length;
2453
+ if ( !len ) {
2454
+ return;
2455
+ }
2456
+ for ( var i=0; i < len; i++ ) {
2457
+ var item = items[i];
2458
+ item.hide();
2459
+ }
2460
+ };
2461
+
2462
+ /**
2463
+ * get Outlayer.Item, given an Element
2464
+ * @param {Element} elem
2465
+ * @param {Function} callback
2466
+ * @returns {Outlayer.Item} item
2467
+ */
2468
+ Outlayer.prototype.getItem = function( elem ) {
2469
+ // loop through items to get the one that matches
2470
+ for ( var i=0, len = this.items.length; i < len; i++ ) {
2471
+ var item = this.items[i];
2472
+ if ( item.element === elem ) {
2473
+ // return item
2474
+ return item;
2475
+ }
2476
+ }
2477
+ };
2478
+
2479
+ /**
2480
+ * get collection of Outlayer.Items, given Elements
2481
+ * @param {Array} elems
2482
+ * @returns {Array} items - Outlayer.Items
2483
+ */
2484
+ Outlayer.prototype.getItems = function( elems ) {
2485
+ if ( !elems || !elems.length ) {
2486
+ return;
2487
+ }
2488
+ var items = [];
2489
+ for ( var i=0, len = elems.length; i < len; i++ ) {
2490
+ var elem = elems[i];
2491
+ var item = this.getItem( elem );
2492
+ if ( item ) {
2493
+ items.push( item );
2494
+ }
2495
+ }
2496
+
2497
+ return items;
2498
+ };
2499
+
2500
+ /**
2501
+ * remove element(s) from instance and DOM
2502
+ * @param {Array or NodeList or Element} elems
2503
+ */
2504
+ Outlayer.prototype.remove = function( elems ) {
2505
+ elems = makeArray( elems );
2506
+
2507
+ var removeItems = this.getItems( elems );
2508
+ // bail if no items to remove
2509
+ if ( !removeItems || !removeItems.length ) {
2510
+ return;
2511
+ }
2512
+
2513
+ this._itemsOn( removeItems, 'remove', function() {
2514
+ this.emitEvent( 'removeComplete', [ this, removeItems ] );
2515
+ });
2516
+
2517
+ for ( var i=0, len = removeItems.length; i < len; i++ ) {
2518
+ var item = removeItems[i];
2519
+ item.remove();
2520
+ // remove item from collection
2521
+ removeFrom( item, this.items );
2522
+ }
2523
+ };
2524
+
2525
+ // ----- destroy ----- //
2526
+
2527
+ // remove and disable Outlayer instance
2528
+ Outlayer.prototype.destroy = function() {
2529
+ // clean up dynamic styles
2530
+ var style = this.element.style;
2531
+ style.height = '';
2532
+ style.position = '';
2533
+ style.width = '';
2534
+ // destroy items
2535
+ for ( var i=0, len = this.items.length; i < len; i++ ) {
2536
+ var item = this.items[i];
2537
+ item.destroy();
2538
+ }
2539
+
2540
+ this.unbindResize();
2541
+
2542
+ delete this.element.outlayerGUID;
2543
+ // remove data for jQuery
2544
+ if ( jQuery ) {
2545
+ jQuery.removeData( this.element, this.constructor.namespace );
2546
+ }
2547
+
2548
+ };
2549
+
2550
+ // -------------------------- data -------------------------- //
2551
+
2552
+ /**
2553
+ * get Outlayer instance from element
2554
+ * @param {Element} elem
2555
+ * @returns {Outlayer}
2556
+ */
2557
+ Outlayer.data = function( elem ) {
2558
+ var id = elem && elem.outlayerGUID;
2559
+ return id && instances[ id ];
2560
+ };
2561
+
2562
+
2563
+ // -------------------------- create Outlayer class -------------------------- //
2564
+
2565
+ /**
2566
+ * create a layout class
2567
+ * @param {String} namespace
2568
+ */
2569
+ Outlayer.create = function( namespace, options ) {
2570
+ // sub-class Outlayer
2571
+ function Layout() {
2572
+ Outlayer.apply( this, arguments );
2573
+ }
2574
+ // inherit Outlayer prototype, use Object.create if there
2575
+ if ( Object.create ) {
2576
+ Layout.prototype = Object.create( Outlayer.prototype );
2577
+ } else {
2578
+ extend( Layout.prototype, Outlayer.prototype );
2579
+ }
2580
+ // set contructor, used for namespace and Item
2581
+ Layout.prototype.constructor = Layout;
2582
+
2583
+ Layout.defaults = extend( {}, Outlayer.defaults );
2584
+ // apply new options
2585
+ extend( Layout.defaults, options );
2586
+ // keep prototype.settings for backwards compatibility (Packery v1.2.0)
2587
+ Layout.prototype.settings = {};
2588
+
2589
+ Layout.namespace = namespace;
2590
+
2591
+ Layout.data = Outlayer.data;
2592
+
2593
+ // sub-class Item
2594
+ Layout.Item = function LayoutItem() {
2595
+ Item.apply( this, arguments );
2596
+ };
2597
+
2598
+ Layout.Item.prototype = new Item();
2599
+
2600
+ // -------------------------- declarative -------------------------- //
2601
+
2602
+ /**
2603
+ * allow user to initialize Outlayer via .js-namespace class
2604
+ * options are parsed from data-namespace-option attribute
2605
+ */
2606
+ docReady( function() {
2607
+ var dashedNamespace = toDashed( namespace );
2608
+ var elems = document.querySelectorAll( '.js-' + dashedNamespace );
2609
+ var dataAttr = 'data-' + dashedNamespace + '-options';
2610
+
2611
+ for ( var i=0, len = elems.length; i < len; i++ ) {
2612
+ var elem = elems[i];
2613
+ var attr = elem.getAttribute( dataAttr );
2614
+ var options;
2615
+ try {
2616
+ options = attr && JSON.parse( attr );
2617
+ } catch ( error ) {
2618
+ // log error, do not initialize
2619
+ if ( console ) {
2620
+ console.error( 'Error parsing ' + dataAttr + ' on ' +
2621
+ elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' +
2622
+ error );
2623
+ }
2624
+ continue;
2625
+ }
2626
+ // initialize
2627
+ var instance = new Layout( elem, options );
2628
+ // make available via $().data('layoutname')
2629
+ if ( jQuery ) {
2630
+ jQuery.data( elem, namespace, instance );
2631
+ }
2632
+ }
2633
+ });
2634
+
2635
+ // -------------------------- jQuery bridge -------------------------- //
2636
+
2637
+ // make into jQuery plugin
2638
+ if ( jQuery && jQuery.bridget ) {
2639
+ jQuery.bridget( namespace, Layout );
2640
+ }
2641
+
2642
+ return Layout;
2643
+ };
2644
+
2645
+ // ----- fin ----- //
2646
+
2647
+ // back in global
2648
+ Outlayer.Item = Item;
2649
+
2650
+ return Outlayer;
2651
+
2652
+ }
2653
+
2654
+ // -------------------------- transport -------------------------- //
2655
+
2656
+ if ( typeof define === 'function' && define.amd ) {
2657
+ // AMD
2658
+ define( 'outlayer/outlayer',[
2659
+ 'eventie/eventie',
2660
+ 'doc-ready/doc-ready',
2661
+ 'eventEmitter/EventEmitter',
2662
+ 'get-size/get-size',
2663
+ 'matches-selector/matches-selector',
2664
+ './item'
2665
+ ],
2666
+ outlayerDefinition );
2667
+ } else {
2668
+ // browser global
2669
+ window.Outlayer = outlayerDefinition(
2670
+ window.eventie,
2671
+ window.docReady,
2672
+ window.EventEmitter,
2673
+ window.getSize,
2674
+ window.matchesSelector,
2675
+ window.Outlayer.Item
2676
+ );
2677
+ }
2678
+
2679
+ })( window );
2680
+
2681
+ /*!
2682
+ * Masonry v3.1.5
2683
+ * Cascading grid layout library
2684
+ * http://masonry.desandro.com
2685
+ * MIT License
2686
+ * by David DeSandro
2687
+ */
2688
+
2689
+ ( function( window ) {
2690
+
2691
+
2692
+
2693
+ // -------------------------- helpers -------------------------- //
2694
+
2695
+ var indexOf = Array.prototype.indexOf ?
2696
+ function( items, value ) {
2697
+ return items.indexOf( value );
2698
+ } :
2699
+ function ( items, value ) {
2700
+ for ( var i=0, len = items.length; i < len; i++ ) {
2701
+ var item = items[i];
2702
+ if ( item === value ) {
2703
+ return i;
2704
+ }
2705
+ }
2706
+ return -1;
2707
+ };
2708
+
2709
+ // -------------------------- masonryDefinition -------------------------- //
2710
+
2711
+ // used for AMD definition and requires
2712
+ function masonryDefinition( Outlayer, getSize ) {
2713
+ // create an Outlayer layout class
2714
+ var Masonry = Outlayer.create('masonry');
2715
+
2716
+ Masonry.prototype._resetLayout = function() {
2717
+ this.getSize();
2718
+ this._getMeasurement( 'columnWidth', 'outerWidth' );
2719
+ this._getMeasurement( 'gutter', 'outerWidth' );
2720
+ this.measureColumns();
2721
+
2722
+ // reset column Y
2723
+ var i = this.cols;
2724
+ this.colYs = [];
2725
+ while (i--) {
2726
+ this.colYs.push( 0 );
2727
+ }
2728
+
2729
+ this.maxY = 0;
2730
+ };
2731
+
2732
+ Masonry.prototype.measureColumns = function() {
2733
+ this.getContainerWidth();
2734
+ // if columnWidth is 0, default to outerWidth of first item
2735
+ if ( !this.columnWidth ) {
2736
+ var firstItem = this.items[0];
2737
+ var firstItemElem = firstItem && firstItem.element;
2738
+ // columnWidth fall back to item of first element
2739
+ this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
2740
+ // if first elem has no width, default to size of container
2741
+ this.containerWidth;
2742
+ }
2743
+
2744
+ this.columnWidth += this.gutter;
2745
+
2746
+ this.cols = Math.floor( ( this.containerWidth + this.gutter ) / this.columnWidth );
2747
+ this.cols = Math.max( this.cols, 1 );
2748
+ };
2749
+
2750
+ Masonry.prototype.getContainerWidth = function() {
2751
+ // container is parent if fit width
2752
+ var container = this.options.isFitWidth ? this.element.parentNode : this.element;
2753
+ // check that this.size and size are there
2754
+ // IE8 triggers resize on body size change, so they might not be
2755
+ var size = getSize( container );
2756
+ this.containerWidth = size && size.innerWidth;
2757
+ };
2758
+
2759
+ Masonry.prototype._getItemLayoutPosition = function( item ) {
2760
+ item.getSize();
2761
+ // how many columns does this brick span
2762
+ var remainder = item.size.outerWidth % this.columnWidth;
2763
+ var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
2764
+ // round if off by 1 pixel, otherwise use ceil
2765
+ var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
2766
+ colSpan = Math.min( colSpan, this.cols );
2767
+
2768
+ var colGroup = this._getColGroup( colSpan );
2769
+ // get the minimum Y value from the columns
2770
+ var minimumY = Math.min.apply( Math, colGroup );
2771
+ var shortColIndex = indexOf( colGroup, minimumY );
2772
+
2773
+ // position the brick
2774
+ var position = {
2775
+ x: this.columnWidth * shortColIndex,
2776
+ y: minimumY
2777
+ };
2778
+
2779
+ // apply setHeight to necessary columns
2780
+ var setHeight = minimumY + item.size.outerHeight;
2781
+ var setSpan = this.cols + 1 - colGroup.length;
2782
+ for ( var i = 0; i < setSpan; i++ ) {
2783
+ this.colYs[ shortColIndex + i ] = setHeight;
2784
+ }
2785
+
2786
+ return position;
2787
+ };
2788
+
2789
+ /**
2790
+ * @param {Number} colSpan - number of columns the element spans
2791
+ * @returns {Array} colGroup
2792
+ */
2793
+ Masonry.prototype._getColGroup = function( colSpan ) {
2794
+ if ( colSpan < 2 ) {
2795
+ // if brick spans only one column, use all the column Ys
2796
+ return this.colYs;
2797
+ }
2798
+
2799
+ var colGroup = [];
2800
+ // how many different places could this brick fit horizontally
2801
+ var groupCount = this.cols + 1 - colSpan;
2802
+ // for each group potential horizontal position
2803
+ for ( var i = 0; i < groupCount; i++ ) {
2804
+ // make an array of colY values for that one group
2805
+ var groupColYs = this.colYs.slice( i, i + colSpan );
2806
+ // and get the max value of the array
2807
+ colGroup[i] = Math.max.apply( Math, groupColYs );
2808
+ }
2809
+ return colGroup;
2810
+ };
2811
+
2812
+ Masonry.prototype._manageStamp = function( stamp ) {
2813
+ var stampSize = getSize( stamp );
2814
+ var offset = this._getElementOffset( stamp );
2815
+ // get the columns that this stamp affects
2816
+ var firstX = this.options.isOriginLeft ? offset.left : offset.right;
2817
+ var lastX = firstX + stampSize.outerWidth;
2818
+ var firstCol = Math.floor( firstX / this.columnWidth );
2819
+ firstCol = Math.max( 0, firstCol );
2820
+ var lastCol = Math.floor( lastX / this.columnWidth );
2821
+ // lastCol should not go over if multiple of columnWidth #425
2822
+ lastCol -= lastX % this.columnWidth ? 0 : 1;
2823
+ lastCol = Math.min( this.cols - 1, lastCol );
2824
+ // set colYs to bottom of the stamp
2825
+ var stampMaxY = ( this.options.isOriginTop ? offset.top : offset.bottom ) +
2826
+ stampSize.outerHeight;
2827
+ for ( var i = firstCol; i <= lastCol; i++ ) {
2828
+ this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
2829
+ }
2830
+ };
2831
+
2832
+ Masonry.prototype._getContainerSize = function() {
2833
+ this.maxY = Math.max.apply( Math, this.colYs );
2834
+ var size = {
2835
+ height: this.maxY
2836
+ };
2837
+
2838
+ if ( this.options.isFitWidth ) {
2839
+ size.width = this._getContainerFitWidth();
2840
+ }
2841
+
2842
+ return size;
2843
+ };
2844
+
2845
+ Masonry.prototype._getContainerFitWidth = function() {
2846
+ var unusedCols = 0;
2847
+ // count unused columns
2848
+ var i = this.cols;
2849
+ while ( --i ) {
2850
+ if ( this.colYs[i] !== 0 ) {
2851
+ break;
2852
+ }
2853
+ unusedCols++;
2854
+ }
2855
+ // fit container to columns that have been used
2856
+ return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
2857
+ };
2858
+
2859
+ Masonry.prototype.needsResizeLayout = function() {
2860
+ var previousWidth = this.containerWidth;
2861
+ this.getContainerWidth();
2862
+ return previousWidth !== this.containerWidth;
2863
+ };
2864
+
2865
+ return Masonry;
2866
+ }
2867
+
2868
+ // -------------------------- transport -------------------------- //
2869
+
2870
+ if ( typeof define === 'function' && define.amd ) {
2871
+ // AMD
2872
+ define( [
2873
+ 'outlayer/outlayer',
2874
+ 'get-size/get-size'
2875
+ ],
2876
+ masonryDefinition );
2877
+ } else {
2878
+ // browser global
2879
+ window.Masonry = masonryDefinition(
2880
+ window.Outlayer,
2881
+ window.getSize
2882
+ );
2883
+ }
2884
+
2885
+ })( window );