packery-rails 1.2.4

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: a0581871b683618307059bab7583350c7216572a
4
+ data.tar.gz: 3242208df7205b1c245dfa3d1b3b4d0cfe495480
5
+ SHA512:
6
+ metadata.gz: 867afb6b13ac555cb7e88a7df529d1d141e6fc52875d358ae1a772ca36cc20b86aacdba7fb26a038958f94095940df094b6c70aa570b5c86b4762a3bb416fea2
7
+ data.tar.gz: cfa44c526dcc6221d7c5290dd700dc545d338b9845f68a8cdcfb6f171d2846c30e5652356a1e8fac0862411e2b3e09643e70192bc61bb3dfcab6fe281781325d
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,48 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ packery-rails (1.2.4)
5
+ railties (>= 3.1.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ actionpack (4.1.8)
11
+ actionview (= 4.1.8)
12
+ activesupport (= 4.1.8)
13
+ rack (~> 1.5.2)
14
+ rack-test (~> 0.6.2)
15
+ actionview (4.1.8)
16
+ activesupport (= 4.1.8)
17
+ builder (~> 3.1)
18
+ erubis (~> 2.7.0)
19
+ activesupport (4.1.8)
20
+ i18n (~> 0.6, >= 0.6.9)
21
+ json (~> 1.7, >= 1.7.7)
22
+ minitest (~> 5.1)
23
+ thread_safe (~> 0.1)
24
+ tzinfo (~> 1.1)
25
+ builder (3.2.2)
26
+ erubis (2.7.0)
27
+ i18n (0.6.11)
28
+ json (1.8.1)
29
+ minitest (5.4.3)
30
+ rack (1.5.2)
31
+ rack-test (0.6.2)
32
+ rack (>= 1.0)
33
+ railties (4.1.8)
34
+ actionpack (= 4.1.8)
35
+ activesupport (= 4.1.8)
36
+ rake (>= 0.8.7)
37
+ thor (>= 0.18.1, < 2.0)
38
+ rake (10.3.2)
39
+ thor (0.19.1)
40
+ thread_safe (0.3.4)
41
+ tzinfo (1.2.2)
42
+ thread_safe (~> 0.1)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ packery-rails!
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Leonid Beder
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,69 @@
1
+ # packery-rails
2
+
3
+ This is a bundled version of the [packery](https://github.com/metafizzy/packery) library.
4
+
5
+ ## Install
6
+
7
+ In your Gemfile, add:
8
+
9
+ ```ruby
10
+ gem 'packery-rails'
11
+ ```
12
+
13
+ Add it to your JavaScript manifest file:
14
+
15
+ ``` js
16
+ //= require packery.pkgd
17
+ ```
18
+
19
+ ## Commercial license
20
+
21
+ Packery may be used in commercial projects and applications with the one-time purchase of a commercial license. If you are paid to do your job, and part of your job is implementing Packery, a commercial license is required.
22
+
23
+ http://packery.metafizzy.co/license.html
24
+
25
+ For non-commercial, personal, or open source projects and applications, you may use Packery under the terms of the [GPL v3 License](http://choosealicense.com/licenses/gpl-v3/). You may use Packery for free.
26
+
27
+
28
+ ## Initialize
29
+
30
+ ### in JavaScript
31
+
32
+ ``` js
33
+ var container = document.querySelector('#container');
34
+ var myPackery = new Packery( container, {
35
+ // options...
36
+ });
37
+ ```
38
+
39
+ ### in HTML
40
+
41
+ Add a class of `js-packery` to your element. Options can be set in JSON in `data-packery-options`.
42
+
43
+ ``` html
44
+ <div class="js-packery" data-packery-options='{ "itemSelector": ".item" }'>
45
+ ...
46
+ </div>
47
+
48
+ ## License
49
+
50
+ The MIT License (MIT)
51
+
52
+ Copyright (c) 2014
53
+
54
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
55
+ this software and associated documentation files (the "Software"), to deal in
56
+ the Software without restriction, including without limitation the rights to
57
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
58
+ the Software, and to permit persons to whom the Software is furnished to do so,
59
+ subject to the following conditions:
60
+
61
+ The above copyright notice and this permission notice shall be included in all
62
+ copies or substantial portions of the Software.
63
+
64
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
65
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
66
+ FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
67
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
68
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
69
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,8 @@
1
+ require 'packery/rails/version'
2
+
3
+ module Packery
4
+ module Rails
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Packery
2
+ module Rails
3
+ VERSION = '1.2.4'.freeze
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+ require 'packery/rails/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'packery-rails'
6
+ s.version = Packery::Rails::VERSION
7
+ s.authors = ['Leonid Beder']
8
+ s.email = ['leonid.beder@gmail.com']
9
+ s.license = 'MIT'
10
+ s.homepage = ''
11
+ s.summary = 'Bin-packing layout library http://packery.metafizzy.co'
12
+ s.description = 'Bin-packing layout library http://packery.metafizzy.co.'
13
+
14
+ s.files = `git ls-files`.split($/)
15
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ s.test_files = s.files.grep(%r{^(test|s|features)/})
17
+ s.require_paths = ['lib']
18
+
19
+ s.add_dependency 'railties', '>= 3.1.0'
20
+ end
@@ -0,0 +1,3729 @@
1
+ /*!
2
+ * Packery PACKAGED v1.2.4
3
+ * bin-packing layout library
4
+ * http://packery.metafizzy.co
5
+ *
6
+ * Commercial use requires one-time purchase of a commercial license
7
+ * http://packery.metafizzy.co/license.html
8
+ *
9
+ * Non-commercial use is licensed under the GPL v3 License
10
+ *
11
+ * Copyright 2014 Metafizzy
12
+ */
13
+
14
+ /**
15
+ * Bridget makes jQuery widgets
16
+ * v1.0.1
17
+ */
18
+
19
+ ( function( window ) {
20
+
21
+
22
+
23
+ // -------------------------- utils -------------------------- //
24
+
25
+ var slice = Array.prototype.slice;
26
+
27
+ function noop() {}
28
+
29
+ // -------------------------- definition -------------------------- //
30
+
31
+ function defineBridget( $ ) {
32
+
33
+ // bail if no jQuery
34
+ if ( !$ ) {
35
+ return;
36
+ }
37
+
38
+ // -------------------------- addOptionMethod -------------------------- //
39
+
40
+ /**
41
+ * adds option method -> $().plugin('option', {...})
42
+ * @param {Function} PluginClass - constructor class
43
+ */
44
+ function addOptionMethod( PluginClass ) {
45
+ // don't overwrite original option method
46
+ if ( PluginClass.prototype.option ) {
47
+ return;
48
+ }
49
+
50
+ // option setter
51
+ PluginClass.prototype.option = function( opts ) {
52
+ // bail out if not an object
53
+ if ( !$.isPlainObject( opts ) ){
54
+ return;
55
+ }
56
+ this.options = $.extend( true, this.options, opts );
57
+ };
58
+ }
59
+
60
+
61
+ // -------------------------- plugin bridge -------------------------- //
62
+
63
+ // helper function for logging errors
64
+ // $.error breaks jQuery chaining
65
+ var logError = typeof console === 'undefined' ? noop :
66
+ function( message ) {
67
+ console.error( message );
68
+ };
69
+
70
+ /**
71
+ * jQuery plugin bridge, access methods like $elem.plugin('method')
72
+ * @param {String} namespace - plugin name
73
+ * @param {Function} PluginClass - constructor class
74
+ */
75
+ function bridge( namespace, PluginClass ) {
76
+ // add to jQuery fn namespace
77
+ $.fn[ namespace ] = function( options ) {
78
+ if ( typeof options === 'string' ) {
79
+ // call plugin method when first argument is a string
80
+ // get arguments for method
81
+ var args = slice.call( arguments, 1 );
82
+
83
+ for ( var i=0, len = this.length; i < len; i++ ) {
84
+ var elem = this[i];
85
+ var instance = $.data( elem, namespace );
86
+ if ( !instance ) {
87
+ logError( "cannot call methods on " + namespace + " prior to initialization; " +
88
+ "attempted to call '" + options + "'" );
89
+ continue;
90
+ }
91
+ if ( !$.isFunction( instance[options] ) || options.charAt(0) === '_' ) {
92
+ logError( "no such method '" + options + "' for " + namespace + " instance" );
93
+ continue;
94
+ }
95
+
96
+ // trigger method with arguments
97
+ var returnValue = instance[ options ].apply( instance, args );
98
+
99
+ // break look and return first value if provided
100
+ if ( returnValue !== undefined ) {
101
+ return returnValue;
102
+ }
103
+ }
104
+ // return this if no return value
105
+ return this;
106
+ } else {
107
+ return this.each( function() {
108
+ var instance = $.data( this, namespace );
109
+ if ( instance ) {
110
+ // apply options & init
111
+ instance.option( options );
112
+ instance._init();
113
+ } else {
114
+ // initialize new instance
115
+ instance = new PluginClass( this, options );
116
+ $.data( this, namespace, instance );
117
+ }
118
+ });
119
+ }
120
+ };
121
+
122
+ }
123
+
124
+ // -------------------------- bridget -------------------------- //
125
+
126
+ /**
127
+ * converts a Prototypical class into a proper jQuery plugin
128
+ * the class must have a ._init method
129
+ * @param {String} namespace - plugin name, used in $().pluginName
130
+ * @param {Function} PluginClass - constructor class
131
+ */
132
+ $.bridget = function( namespace, PluginClass ) {
133
+ addOptionMethod( PluginClass );
134
+ bridge( namespace, PluginClass );
135
+ };
136
+
137
+ return $.bridget;
138
+
139
+ }
140
+
141
+ // transport
142
+ if ( typeof define === 'function' && define.amd ) {
143
+ // AMD
144
+ define( 'jquery-bridget/jquery.bridget',[ 'jquery' ], defineBridget );
145
+ } else {
146
+ // get jquery from browser global
147
+ defineBridget( window.jQuery );
148
+ }
149
+
150
+ })( window );
151
+
152
+ /*!
153
+ * classie v1.0.1
154
+ * class helper functions
155
+ * from bonzo https://github.com/ded/bonzo
156
+ * MIT license
157
+ *
158
+ * classie.has( elem, 'my-class' ) -> true/false
159
+ * classie.add( elem, 'my-new-class' )
160
+ * classie.remove( elem, 'my-unwanted-class' )
161
+ * classie.toggle( elem, 'my-class' )
162
+ */
163
+
164
+ /*jshint browser: true, strict: true, undef: true, unused: true */
165
+ /*global define: false, module: false */
166
+
167
+ ( function( window ) {
168
+
169
+
170
+
171
+ // class helper functions from bonzo https://github.com/ded/bonzo
172
+
173
+ function classReg( className ) {
174
+ return new RegExp("(^|\\s+)" + className + "(\\s+|$)");
175
+ }
176
+
177
+ // classList support for class management
178
+ // altho to be fair, the api sucks because it won't accept multiple classes at once
179
+ var hasClass, addClass, removeClass;
180
+
181
+ if ( 'classList' in document.documentElement ) {
182
+ hasClass = function( elem, c ) {
183
+ return elem.classList.contains( c );
184
+ };
185
+ addClass = function( elem, c ) {
186
+ elem.classList.add( c );
187
+ };
188
+ removeClass = function( elem, c ) {
189
+ elem.classList.remove( c );
190
+ };
191
+ }
192
+ else {
193
+ hasClass = function( elem, c ) {
194
+ return classReg( c ).test( elem.className );
195
+ };
196
+ addClass = function( elem, c ) {
197
+ if ( !hasClass( elem, c ) ) {
198
+ elem.className = elem.className + ' ' + c;
199
+ }
200
+ };
201
+ removeClass = function( elem, c ) {
202
+ elem.className = elem.className.replace( classReg( c ), ' ' );
203
+ };
204
+ }
205
+
206
+ function toggleClass( elem, c ) {
207
+ var fn = hasClass( elem, c ) ? removeClass : addClass;
208
+ fn( elem, c );
209
+ }
210
+
211
+ var classie = {
212
+ // full names
213
+ hasClass: hasClass,
214
+ addClass: addClass,
215
+ removeClass: removeClass,
216
+ toggleClass: toggleClass,
217
+ // short names
218
+ has: hasClass,
219
+ add: addClass,
220
+ remove: removeClass,
221
+ toggle: toggleClass
222
+ };
223
+
224
+ // transport
225
+ if ( typeof define === 'function' && define.amd ) {
226
+ // AMD
227
+ define( 'classie/classie',classie );
228
+ } else if ( typeof exports === 'object' ) {
229
+ // CommonJS
230
+ module.exports = classie;
231
+ } else {
232
+ // browser global
233
+ window.classie = classie;
234
+ }
235
+
236
+ })( window );
237
+
238
+ /*!
239
+ * getStyleProperty v1.0.3
240
+ * original by kangax
241
+ * http://perfectionkills.com/feature-testing-css-properties/
242
+ */
243
+
244
+ /*jshint browser: true, strict: true, undef: true */
245
+ /*global define: false, exports: false, module: false */
246
+
247
+ ( function( window ) {
248
+
249
+
250
+
251
+ var prefixes = 'Webkit Moz ms Ms O'.split(' ');
252
+ var docElemStyle = document.documentElement.style;
253
+
254
+ function getStyleProperty( propName ) {
255
+ if ( !propName ) {
256
+ return;
257
+ }
258
+
259
+ // test standard property first
260
+ if ( typeof docElemStyle[ propName ] === 'string' ) {
261
+ return propName;
262
+ }
263
+
264
+ // capitalize
265
+ propName = propName.charAt(0).toUpperCase() + propName.slice(1);
266
+
267
+ // test vendor specific properties
268
+ var prefixed;
269
+ for ( var i=0, len = prefixes.length; i < len; i++ ) {
270
+ prefixed = prefixes[i] + propName;
271
+ if ( typeof docElemStyle[ prefixed ] === 'string' ) {
272
+ return prefixed;
273
+ }
274
+ }
275
+ }
276
+
277
+ // transport
278
+ if ( typeof define === 'function' && define.amd ) {
279
+ // AMD
280
+ define( 'get-style-property/get-style-property',[],function() {
281
+ return getStyleProperty;
282
+ });
283
+ } else if ( typeof exports === 'object' ) {
284
+ // CommonJS for Component
285
+ module.exports = getStyleProperty;
286
+ } else {
287
+ // browser global
288
+ window.getStyleProperty = getStyleProperty;
289
+ }
290
+
291
+ })( window );
292
+
293
+ /**
294
+ * getSize v1.1.7
295
+ * measure size of elements
296
+ */
297
+
298
+ /*jshint browser: true, strict: true, undef: true, unused: true */
299
+ /*global define: false, exports: false, require: false, module: false */
300
+
301
+ ( function( window, undefined ) {
302
+
303
+
304
+
305
+ // -------------------------- helpers -------------------------- //
306
+
307
+ var getComputedStyle = window.getComputedStyle;
308
+ var getStyle = getComputedStyle ?
309
+ function( elem ) {
310
+ return getComputedStyle( elem, null );
311
+ } :
312
+ function( elem ) {
313
+ return elem.currentStyle;
314
+ };
315
+
316
+ // get a number from a string, not a percentage
317
+ function getStyleSize( value ) {
318
+ var num = parseFloat( value );
319
+ // not a percent like '100%', and a number
320
+ var isValid = value.indexOf('%') === -1 && !isNaN( num );
321
+ return isValid && num;
322
+ }
323
+
324
+ // -------------------------- measurements -------------------------- //
325
+
326
+ var measurements = [
327
+ 'paddingLeft',
328
+ 'paddingRight',
329
+ 'paddingTop',
330
+ 'paddingBottom',
331
+ 'marginLeft',
332
+ 'marginRight',
333
+ 'marginTop',
334
+ 'marginBottom',
335
+ 'borderLeftWidth',
336
+ 'borderRightWidth',
337
+ 'borderTopWidth',
338
+ 'borderBottomWidth'
339
+ ];
340
+
341
+ function getZeroSize() {
342
+ var size = {
343
+ width: 0,
344
+ height: 0,
345
+ innerWidth: 0,
346
+ innerHeight: 0,
347
+ outerWidth: 0,
348
+ outerHeight: 0
349
+ };
350
+ for ( var i=0, len = measurements.length; i < len; i++ ) {
351
+ var measurement = measurements[i];
352
+ size[ measurement ] = 0;
353
+ }
354
+ return size;
355
+ }
356
+
357
+
358
+
359
+ function defineGetSize( getStyleProperty ) {
360
+
361
+ // -------------------------- box sizing -------------------------- //
362
+
363
+ var boxSizingProp = getStyleProperty('boxSizing');
364
+ var isBoxSizeOuter;
365
+
366
+ /**
367
+ * WebKit measures the outer-width on style.width on border-box elems
368
+ * IE & Firefox measures the inner-width
369
+ */
370
+ ( function() {
371
+ if ( !boxSizingProp ) {
372
+ return;
373
+ }
374
+
375
+ var div = document.createElement('div');
376
+ div.style.width = '200px';
377
+ div.style.padding = '1px 2px 3px 4px';
378
+ div.style.borderStyle = 'solid';
379
+ div.style.borderWidth = '1px 2px 3px 4px';
380
+ div.style[ boxSizingProp ] = 'border-box';
381
+
382
+ var body = document.body || document.documentElement;
383
+ body.appendChild( div );
384
+ var style = getStyle( div );
385
+
386
+ isBoxSizeOuter = getStyleSize( style.width ) === 200;
387
+ body.removeChild( div );
388
+ })();
389
+
390
+
391
+ // -------------------------- getSize -------------------------- //
392
+
393
+ function getSize( elem ) {
394
+ // use querySeletor if elem is string
395
+ if ( typeof elem === 'string' ) {
396
+ elem = document.querySelector( elem );
397
+ }
398
+
399
+ // do not proceed on non-objects
400
+ if ( !elem || typeof elem !== 'object' || !elem.nodeType ) {
401
+ return;
402
+ }
403
+
404
+ var style = getStyle( elem );
405
+
406
+ // if hidden, everything is 0
407
+ if ( style.display === 'none' ) {
408
+ return getZeroSize();
409
+ }
410
+
411
+ var size = {};
412
+ size.width = elem.offsetWidth;
413
+ size.height = elem.offsetHeight;
414
+
415
+ var isBorderBox = size.isBorderBox = !!( boxSizingProp &&
416
+ style[ boxSizingProp ] && style[ boxSizingProp ] === 'border-box' );
417
+
418
+ // get all measurements
419
+ for ( var i=0, len = measurements.length; i < len; i++ ) {
420
+ var measurement = measurements[i];
421
+ var value = style[ measurement ];
422
+ value = mungeNonPixel( elem, value );
423
+ var num = parseFloat( value );
424
+ // any 'auto', 'medium' value will be 0
425
+ size[ measurement ] = !isNaN( num ) ? num : 0;
426
+ }
427
+
428
+ var paddingWidth = size.paddingLeft + size.paddingRight;
429
+ var paddingHeight = size.paddingTop + size.paddingBottom;
430
+ var marginWidth = size.marginLeft + size.marginRight;
431
+ var marginHeight = size.marginTop + size.marginBottom;
432
+ var borderWidth = size.borderLeftWidth + size.borderRightWidth;
433
+ var borderHeight = size.borderTopWidth + size.borderBottomWidth;
434
+
435
+ var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
436
+
437
+ // overwrite width and height if we can get it from style
438
+ var styleWidth = getStyleSize( style.width );
439
+ if ( styleWidth !== false ) {
440
+ size.width = styleWidth +
441
+ // add padding and border unless it's already including it
442
+ ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
443
+ }
444
+
445
+ var styleHeight = getStyleSize( style.height );
446
+ if ( styleHeight !== false ) {
447
+ size.height = styleHeight +
448
+ // add padding and border unless it's already including it
449
+ ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
450
+ }
451
+
452
+ size.innerWidth = size.width - ( paddingWidth + borderWidth );
453
+ size.innerHeight = size.height - ( paddingHeight + borderHeight );
454
+
455
+ size.outerWidth = size.width + marginWidth;
456
+ size.outerHeight = size.height + marginHeight;
457
+
458
+ return size;
459
+ }
460
+
461
+ // IE8 returns percent values, not pixels
462
+ // taken from jQuery's curCSS
463
+ function mungeNonPixel( elem, value ) {
464
+ // IE8 and has percent value
465
+ if ( getComputedStyle || value.indexOf('%') === -1 ) {
466
+ return value;
467
+ }
468
+ var style = elem.style;
469
+ // Remember the original values
470
+ var left = style.left;
471
+ var rs = elem.runtimeStyle;
472
+ var rsLeft = rs && rs.left;
473
+
474
+ // Put in the new values to get a computed value out
475
+ if ( rsLeft ) {
476
+ rs.left = elem.currentStyle.left;
477
+ }
478
+ style.left = value;
479
+ value = style.pixelLeft;
480
+
481
+ // Revert the changed values
482
+ style.left = left;
483
+ if ( rsLeft ) {
484
+ rs.left = rsLeft;
485
+ }
486
+
487
+ return value;
488
+ }
489
+
490
+ return getSize;
491
+
492
+ }
493
+
494
+ // transport
495
+ if ( typeof define === 'function' && define.amd ) {
496
+ // AMD for RequireJS
497
+ define( 'get-size/get-size',[ 'get-style-property/get-style-property' ], defineGetSize );
498
+ } else if ( typeof exports === 'object' ) {
499
+ // CommonJS for Component
500
+ module.exports = defineGetSize( require('get-style-property') );
501
+ } else {
502
+ // browser global
503
+ window.getSize = defineGetSize( window.getStyleProperty );
504
+ }
505
+
506
+ })( window );
507
+
508
+ /*!
509
+ * eventie v1.0.5
510
+ * event binding helper
511
+ * eventie.bind( elem, 'click', myFn )
512
+ * eventie.unbind( elem, 'click', myFn )
513
+ * MIT license
514
+ */
515
+
516
+ /*jshint browser: true, undef: true, unused: true */
517
+ /*global define: false, module: false */
518
+
519
+ ( function( window ) {
520
+
521
+
522
+
523
+ var docElem = document.documentElement;
524
+
525
+ var bind = function() {};
526
+
527
+ function getIEEvent( obj ) {
528
+ var event = window.event;
529
+ // add event.target
530
+ event.target = event.target || event.srcElement || obj;
531
+ return event;
532
+ }
533
+
534
+ if ( docElem.addEventListener ) {
535
+ bind = function( obj, type, fn ) {
536
+ obj.addEventListener( type, fn, false );
537
+ };
538
+ } else if ( docElem.attachEvent ) {
539
+ bind = function( obj, type, fn ) {
540
+ obj[ type + fn ] = fn.handleEvent ?
541
+ function() {
542
+ var event = getIEEvent( obj );
543
+ fn.handleEvent.call( fn, event );
544
+ } :
545
+ function() {
546
+ var event = getIEEvent( obj );
547
+ fn.call( obj, event );
548
+ };
549
+ obj.attachEvent( "on" + type, obj[ type + fn ] );
550
+ };
551
+ }
552
+
553
+ var unbind = function() {};
554
+
555
+ if ( docElem.removeEventListener ) {
556
+ unbind = function( obj, type, fn ) {
557
+ obj.removeEventListener( type, fn, false );
558
+ };
559
+ } else if ( docElem.detachEvent ) {
560
+ unbind = function( obj, type, fn ) {
561
+ obj.detachEvent( "on" + type, obj[ type + fn ] );
562
+ try {
563
+ delete obj[ type + fn ];
564
+ } catch ( err ) {
565
+ // can't delete window object properties
566
+ obj[ type + fn ] = undefined;
567
+ }
568
+ };
569
+ }
570
+
571
+ var eventie = {
572
+ bind: bind,
573
+ unbind: unbind
574
+ };
575
+
576
+ // ----- module definition ----- //
577
+
578
+ if ( typeof define === 'function' && define.amd ) {
579
+ // AMD
580
+ define( 'eventie/eventie',eventie );
581
+ } else if ( typeof exports === 'object' ) {
582
+ // CommonJS
583
+ module.exports = eventie;
584
+ } else {
585
+ // browser global
586
+ window.eventie = eventie;
587
+ }
588
+
589
+ })( this );
590
+
591
+ /*!
592
+ * docReady v1.0.3
593
+ * Cross browser DOMContentLoaded event emitter
594
+ * MIT license
595
+ */
596
+
597
+ /*jshint browser: true, strict: true, undef: true, unused: true*/
598
+ /*global define: false */
599
+
600
+ ( function( window ) {
601
+
602
+
603
+
604
+ var document = window.document;
605
+ // collection of functions to be triggered on ready
606
+ var queue = [];
607
+
608
+ function docReady( fn ) {
609
+ // throw out non-functions
610
+ if ( typeof fn !== 'function' ) {
611
+ return;
612
+ }
613
+
614
+ if ( docReady.isReady ) {
615
+ // ready now, hit it
616
+ fn();
617
+ } else {
618
+ // queue function when ready
619
+ queue.push( fn );
620
+ }
621
+ }
622
+
623
+ docReady.isReady = false;
624
+
625
+ // triggered on various doc ready events
626
+ function init( event ) {
627
+ // bail if IE8 document is not ready just yet
628
+ var isIE8NotReady = event.type === 'readystatechange' && document.readyState !== 'complete';
629
+ if ( docReady.isReady || isIE8NotReady ) {
630
+ return;
631
+ }
632
+ docReady.isReady = true;
633
+
634
+ // process queue
635
+ for ( var i=0, len = queue.length; i < len; i++ ) {
636
+ var fn = queue[i];
637
+ fn();
638
+ }
639
+ }
640
+
641
+ function defineDocReady( eventie ) {
642
+ eventie.bind( document, 'DOMContentLoaded', init );
643
+ eventie.bind( document, 'readystatechange', init );
644
+ eventie.bind( window, 'load', init );
645
+
646
+ return docReady;
647
+ }
648
+
649
+ // transport
650
+ if ( typeof define === 'function' && define.amd ) {
651
+ // AMD
652
+ // if RequireJS, then doc is already ready
653
+ docReady.isReady = typeof requirejs === 'function';
654
+ define( 'doc-ready/doc-ready',[ 'eventie/eventie' ], defineDocReady );
655
+ } else if ( typeof exports === 'object' ) {
656
+ module.exports = defineDocReady( require('eventie') );
657
+ } else {
658
+ // browser global
659
+ window.docReady = defineDocReady( window.eventie );
660
+ }
661
+
662
+ })( window );
663
+
664
+ /*!
665
+ * EventEmitter v4.2.7 - git.io/ee
666
+ * Oliver Caldwell
667
+ * MIT license
668
+ * @preserve
669
+ */
670
+
671
+ (function () {
672
+
673
+
674
+ /**
675
+ * Class for managing events.
676
+ * Can be extended to provide event functionality in other classes.
677
+ *
678
+ * @class EventEmitter Manages event registering and emitting.
679
+ */
680
+ function EventEmitter() {}
681
+
682
+ // Shortcuts to improve speed and size
683
+ var proto = EventEmitter.prototype;
684
+ var exports = this;
685
+ var originalGlobalValue = exports.EventEmitter;
686
+
687
+ /**
688
+ * Finds the index of the listener for the event in it's storage array.
689
+ *
690
+ * @param {Function[]} listeners Array of listeners to search through.
691
+ * @param {Function} listener Method to look for.
692
+ * @return {Number} Index of the specified listener, -1 if not found
693
+ * @api private
694
+ */
695
+ function indexOfListener(listeners, listener) {
696
+ var i = listeners.length;
697
+ while (i--) {
698
+ if (listeners[i].listener === listener) {
699
+ return i;
700
+ }
701
+ }
702
+
703
+ return -1;
704
+ }
705
+
706
+ /**
707
+ * Alias a method while keeping the context correct, to allow for overwriting of target method.
708
+ *
709
+ * @param {String} name The name of the target method.
710
+ * @return {Function} The aliased method
711
+ * @api private
712
+ */
713
+ function alias(name) {
714
+ return function aliasClosure() {
715
+ return this[name].apply(this, arguments);
716
+ };
717
+ }
718
+
719
+ /**
720
+ * Returns the listener array for the specified event.
721
+ * Will initialise the event object and listener arrays if required.
722
+ * 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.
723
+ * Each property in the object response is an array of listener functions.
724
+ *
725
+ * @param {String|RegExp} evt Name of the event to return the listeners from.
726
+ * @return {Function[]|Object} All listener functions for the event.
727
+ */
728
+ proto.getListeners = function getListeners(evt) {
729
+ var events = this._getEvents();
730
+ var response;
731
+ var key;
732
+
733
+ // Return a concatenated array of all matching events if
734
+ // the selector is a regular expression.
735
+ if (evt instanceof RegExp) {
736
+ response = {};
737
+ for (key in events) {
738
+ if (events.hasOwnProperty(key) && evt.test(key)) {
739
+ response[key] = events[key];
740
+ }
741
+ }
742
+ }
743
+ else {
744
+ response = events[evt] || (events[evt] = []);
745
+ }
746
+
747
+ return response;
748
+ };
749
+
750
+ /**
751
+ * Takes a list of listener objects and flattens it into a list of listener functions.
752
+ *
753
+ * @param {Object[]} listeners Raw listener objects.
754
+ * @return {Function[]} Just the listener functions.
755
+ */
756
+ proto.flattenListeners = function flattenListeners(listeners) {
757
+ var flatListeners = [];
758
+ var i;
759
+
760
+ for (i = 0; i < listeners.length; i += 1) {
761
+ flatListeners.push(listeners[i].listener);
762
+ }
763
+
764
+ return flatListeners;
765
+ };
766
+
767
+ /**
768
+ * 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.
769
+ *
770
+ * @param {String|RegExp} evt Name of the event to return the listeners from.
771
+ * @return {Object} All listener functions for an event in an object.
772
+ */
773
+ proto.getListenersAsObject = function getListenersAsObject(evt) {
774
+ var listeners = this.getListeners(evt);
775
+ var response;
776
+
777
+ if (listeners instanceof Array) {
778
+ response = {};
779
+ response[evt] = listeners;
780
+ }
781
+
782
+ return response || listeners;
783
+ };
784
+
785
+ /**
786
+ * Adds a listener function to the specified event.
787
+ * The listener will not be added if it is a duplicate.
788
+ * If the listener returns true then it will be removed after it is called.
789
+ * If you pass a regular expression as the event name then the listener will be added to all events that match it.
790
+ *
791
+ * @param {String|RegExp} evt Name of the event to attach the listener to.
792
+ * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
793
+ * @return {Object} Current instance of EventEmitter for chaining.
794
+ */
795
+ proto.addListener = function addListener(evt, listener) {
796
+ var listeners = this.getListenersAsObject(evt);
797
+ var listenerIsWrapped = typeof listener === 'object';
798
+ var key;
799
+
800
+ for (key in listeners) {
801
+ if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {
802
+ listeners[key].push(listenerIsWrapped ? listener : {
803
+ listener: listener,
804
+ once: false
805
+ });
806
+ }
807
+ }
808
+
809
+ return this;
810
+ };
811
+
812
+ /**
813
+ * Alias of addListener
814
+ */
815
+ proto.on = alias('addListener');
816
+
817
+ /**
818
+ * Semi-alias of addListener. It will add a listener that will be
819
+ * automatically removed after it's first execution.
820
+ *
821
+ * @param {String|RegExp} evt Name of the event to attach the listener to.
822
+ * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.
823
+ * @return {Object} Current instance of EventEmitter for chaining.
824
+ */
825
+ proto.addOnceListener = function addOnceListener(evt, listener) {
826
+ return this.addListener(evt, {
827
+ listener: listener,
828
+ once: true
829
+ });
830
+ };
831
+
832
+ /**
833
+ * Alias of addOnceListener.
834
+ */
835
+ proto.once = alias('addOnceListener');
836
+
837
+ /**
838
+ * 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.
839
+ * You need to tell it what event names should be matched by a regex.
840
+ *
841
+ * @param {String} evt Name of the event to create.
842
+ * @return {Object} Current instance of EventEmitter for chaining.
843
+ */
844
+ proto.defineEvent = function defineEvent(evt) {
845
+ this.getListeners(evt);
846
+ return this;
847
+ };
848
+
849
+ /**
850
+ * Uses defineEvent to define multiple events.
851
+ *
852
+ * @param {String[]} evts An array of event names to define.
853
+ * @return {Object} Current instance of EventEmitter for chaining.
854
+ */
855
+ proto.defineEvents = function defineEvents(evts) {
856
+ for (var i = 0; i < evts.length; i += 1) {
857
+ this.defineEvent(evts[i]);
858
+ }
859
+ return this;
860
+ };
861
+
862
+ /**
863
+ * Removes a listener function from the specified event.
864
+ * When passed a regular expression as the event name, it will remove the listener from all events that match it.
865
+ *
866
+ * @param {String|RegExp} evt Name of the event to remove the listener from.
867
+ * @param {Function} listener Method to remove from the event.
868
+ * @return {Object} Current instance of EventEmitter for chaining.
869
+ */
870
+ proto.removeListener = function removeListener(evt, listener) {
871
+ var listeners = this.getListenersAsObject(evt);
872
+ var index;
873
+ var key;
874
+
875
+ for (key in listeners) {
876
+ if (listeners.hasOwnProperty(key)) {
877
+ index = indexOfListener(listeners[key], listener);
878
+
879
+ if (index !== -1) {
880
+ listeners[key].splice(index, 1);
881
+ }
882
+ }
883
+ }
884
+
885
+ return this;
886
+ };
887
+
888
+ /**
889
+ * Alias of removeListener
890
+ */
891
+ proto.off = alias('removeListener');
892
+
893
+ /**
894
+ * Adds listeners in bulk using the manipulateListeners method.
895
+ * 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.
896
+ * You can also pass it a regular expression to add the array of listeners to all events that match it.
897
+ * Yeah, this function does quite a bit. That's probably a bad thing.
898
+ *
899
+ * @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.
900
+ * @param {Function[]} [listeners] An optional array of listener functions to add.
901
+ * @return {Object} Current instance of EventEmitter for chaining.
902
+ */
903
+ proto.addListeners = function addListeners(evt, listeners) {
904
+ // Pass through to manipulateListeners
905
+ return this.manipulateListeners(false, evt, listeners);
906
+ };
907
+
908
+ /**
909
+ * Removes listeners in bulk using the manipulateListeners method.
910
+ * 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.
911
+ * You can also pass it an event name and an array of listeners to be removed.
912
+ * You can also pass it a regular expression to remove the listeners from all events that match it.
913
+ *
914
+ * @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.
915
+ * @param {Function[]} [listeners] An optional array of listener functions to remove.
916
+ * @return {Object} Current instance of EventEmitter for chaining.
917
+ */
918
+ proto.removeListeners = function removeListeners(evt, listeners) {
919
+ // Pass through to manipulateListeners
920
+ return this.manipulateListeners(true, evt, listeners);
921
+ };
922
+
923
+ /**
924
+ * 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.
925
+ * The first argument will determine if the listeners are removed (true) or added (false).
926
+ * 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.
927
+ * You can also pass it an event name and an array of listeners to be added/removed.
928
+ * You can also pass it a regular expression to manipulate the listeners of all events that match it.
929
+ *
930
+ * @param {Boolean} remove True if you want to remove listeners, false if you want to add.
931
+ * @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.
932
+ * @param {Function[]} [listeners] An optional array of listener functions to add/remove.
933
+ * @return {Object} Current instance of EventEmitter for chaining.
934
+ */
935
+ proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {
936
+ var i;
937
+ var value;
938
+ var single = remove ? this.removeListener : this.addListener;
939
+ var multiple = remove ? this.removeListeners : this.addListeners;
940
+
941
+ // If evt is an object then pass each of it's properties to this method
942
+ if (typeof evt === 'object' && !(evt instanceof RegExp)) {
943
+ for (i in evt) {
944
+ if (evt.hasOwnProperty(i) && (value = evt[i])) {
945
+ // Pass the single listener straight through to the singular method
946
+ if (typeof value === 'function') {
947
+ single.call(this, i, value);
948
+ }
949
+ else {
950
+ // Otherwise pass back to the multiple function
951
+ multiple.call(this, i, value);
952
+ }
953
+ }
954
+ }
955
+ }
956
+ else {
957
+ // So evt must be a string
958
+ // And listeners must be an array of listeners
959
+ // Loop over it and pass each one to the multiple method
960
+ i = listeners.length;
961
+ while (i--) {
962
+ single.call(this, evt, listeners[i]);
963
+ }
964
+ }
965
+
966
+ return this;
967
+ };
968
+
969
+ /**
970
+ * Removes all listeners from a specified event.
971
+ * If you do not specify an event then all listeners will be removed.
972
+ * That means every event will be emptied.
973
+ * You can also pass a regex to remove all events that match it.
974
+ *
975
+ * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.
976
+ * @return {Object} Current instance of EventEmitter for chaining.
977
+ */
978
+ proto.removeEvent = function removeEvent(evt) {
979
+ var type = typeof evt;
980
+ var events = this._getEvents();
981
+ var key;
982
+
983
+ // Remove different things depending on the state of evt
984
+ if (type === 'string') {
985
+ // Remove all listeners for the specified event
986
+ delete events[evt];
987
+ }
988
+ else if (evt instanceof RegExp) {
989
+ // Remove all events matching the regex.
990
+ for (key in events) {
991
+ if (events.hasOwnProperty(key) && evt.test(key)) {
992
+ delete events[key];
993
+ }
994
+ }
995
+ }
996
+ else {
997
+ // Remove all listeners in all events
998
+ delete this._events;
999
+ }
1000
+
1001
+ return this;
1002
+ };
1003
+
1004
+ /**
1005
+ * Alias of removeEvent.
1006
+ *
1007
+ * Added to mirror the node API.
1008
+ */
1009
+ proto.removeAllListeners = alias('removeEvent');
1010
+
1011
+ /**
1012
+ * Emits an event of your choice.
1013
+ * When emitted, every listener attached to that event will be executed.
1014
+ * If you pass the optional argument array then those arguments will be passed to every listener upon execution.
1015
+ * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.
1016
+ * So they will not arrive within the array on the other side, they will be separate.
1017
+ * You can also pass a regular expression to emit to all events that match it.
1018
+ *
1019
+ * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
1020
+ * @param {Array} [args] Optional array of arguments to be passed to each listener.
1021
+ * @return {Object} Current instance of EventEmitter for chaining.
1022
+ */
1023
+ proto.emitEvent = function emitEvent(evt, args) {
1024
+ var listeners = this.getListenersAsObject(evt);
1025
+ var listener;
1026
+ var i;
1027
+ var key;
1028
+ var response;
1029
+
1030
+ for (key in listeners) {
1031
+ if (listeners.hasOwnProperty(key)) {
1032
+ i = listeners[key].length;
1033
+
1034
+ while (i--) {
1035
+ // If the listener returns true then it shall be removed from the event
1036
+ // The function is executed either with a basic call or an apply if there is an args array
1037
+ listener = listeners[key][i];
1038
+
1039
+ if (listener.once === true) {
1040
+ this.removeListener(evt, listener.listener);
1041
+ }
1042
+
1043
+ response = listener.listener.apply(this, args || []);
1044
+
1045
+ if (response === this._getOnceReturnValue()) {
1046
+ this.removeListener(evt, listener.listener);
1047
+ }
1048
+ }
1049
+ }
1050
+ }
1051
+
1052
+ return this;
1053
+ };
1054
+
1055
+ /**
1056
+ * Alias of emitEvent
1057
+ */
1058
+ proto.trigger = alias('emitEvent');
1059
+
1060
+ /**
1061
+ * 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.
1062
+ * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.
1063
+ *
1064
+ * @param {String|RegExp} evt Name of the event to emit and execute listeners for.
1065
+ * @param {...*} Optional additional arguments to be passed to each listener.
1066
+ * @return {Object} Current instance of EventEmitter for chaining.
1067
+ */
1068
+ proto.emit = function emit(evt) {
1069
+ var args = Array.prototype.slice.call(arguments, 1);
1070
+ return this.emitEvent(evt, args);
1071
+ };
1072
+
1073
+ /**
1074
+ * Sets the current value to check against when executing listeners. If a
1075
+ * listeners return value matches the one set here then it will be removed
1076
+ * after execution. This value defaults to true.
1077
+ *
1078
+ * @param {*} value The new value to check for when executing listeners.
1079
+ * @return {Object} Current instance of EventEmitter for chaining.
1080
+ */
1081
+ proto.setOnceReturnValue = function setOnceReturnValue(value) {
1082
+ this._onceReturnValue = value;
1083
+ return this;
1084
+ };
1085
+
1086
+ /**
1087
+ * Fetches the current value to check against when executing listeners. If
1088
+ * the listeners return value matches this one then it should be removed
1089
+ * automatically. It will return true by default.
1090
+ *
1091
+ * @return {*|Boolean} The current value to check for or the default, true.
1092
+ * @api private
1093
+ */
1094
+ proto._getOnceReturnValue = function _getOnceReturnValue() {
1095
+ if (this.hasOwnProperty('_onceReturnValue')) {
1096
+ return this._onceReturnValue;
1097
+ }
1098
+ else {
1099
+ return true;
1100
+ }
1101
+ };
1102
+
1103
+ /**
1104
+ * Fetches the events object and creates one if required.
1105
+ *
1106
+ * @return {Object} The events storage object.
1107
+ * @api private
1108
+ */
1109
+ proto._getEvents = function _getEvents() {
1110
+ return this._events || (this._events = {});
1111
+ };
1112
+
1113
+ /**
1114
+ * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.
1115
+ *
1116
+ * @return {Function} Non conflicting EventEmitter class.
1117
+ */
1118
+ EventEmitter.noConflict = function noConflict() {
1119
+ exports.EventEmitter = originalGlobalValue;
1120
+ return EventEmitter;
1121
+ };
1122
+
1123
+ // Expose the class either via AMD, CommonJS or the global object
1124
+ if (typeof define === 'function' && define.amd) {
1125
+ define('eventEmitter/EventEmitter',[],function () {
1126
+ return EventEmitter;
1127
+ });
1128
+ }
1129
+ else if (typeof module === 'object' && module.exports){
1130
+ module.exports = EventEmitter;
1131
+ }
1132
+ else {
1133
+ this.EventEmitter = EventEmitter;
1134
+ }
1135
+ }.call(this));
1136
+
1137
+ /**
1138
+ * matchesSelector v1.0.2
1139
+ * matchesSelector( element, '.selector' )
1140
+ * MIT license
1141
+ */
1142
+
1143
+ /*jshint browser: true, strict: true, undef: true, unused: true */
1144
+ /*global define: false, module: false */
1145
+
1146
+ ( function( ElemProto ) {
1147
+
1148
+
1149
+
1150
+ var matchesMethod = ( function() {
1151
+ // check un-prefixed
1152
+ if ( ElemProto.matchesSelector ) {
1153
+ return 'matchesSelector';
1154
+ }
1155
+ // check vendor prefixes
1156
+ var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
1157
+
1158
+ for ( var i=0, len = prefixes.length; i < len; i++ ) {
1159
+ var prefix = prefixes[i];
1160
+ var method = prefix + 'MatchesSelector';
1161
+ if ( ElemProto[ method ] ) {
1162
+ return method;
1163
+ }
1164
+ }
1165
+ })();
1166
+
1167
+ // ----- match ----- //
1168
+
1169
+ function match( elem, selector ) {
1170
+ return elem[ matchesMethod ]( selector );
1171
+ }
1172
+
1173
+ // ----- appendToFragment ----- //
1174
+
1175
+ function checkParent( elem ) {
1176
+ // not needed if already has parent
1177
+ if ( elem.parentNode ) {
1178
+ return;
1179
+ }
1180
+ var fragment = document.createDocumentFragment();
1181
+ fragment.appendChild( elem );
1182
+ }
1183
+
1184
+ // ----- query ----- //
1185
+
1186
+ // fall back to using QSA
1187
+ // thx @jonathantneal https://gist.github.com/3062955
1188
+ function query( elem, selector ) {
1189
+ // append to fragment if no parent
1190
+ checkParent( elem );
1191
+
1192
+ // match elem with all selected elems of parent
1193
+ var elems = elem.parentNode.querySelectorAll( selector );
1194
+ for ( var i=0, len = elems.length; i < len; i++ ) {
1195
+ // return true if match
1196
+ if ( elems[i] === elem ) {
1197
+ return true;
1198
+ }
1199
+ }
1200
+ // otherwise return false
1201
+ return false;
1202
+ }
1203
+
1204
+ // ----- matchChild ----- //
1205
+
1206
+ function matchChild( elem, selector ) {
1207
+ checkParent( elem );
1208
+ return match( elem, selector );
1209
+ }
1210
+
1211
+ // ----- matchesSelector ----- //
1212
+
1213
+ var matchesSelector;
1214
+
1215
+ if ( matchesMethod ) {
1216
+ // IE9 supports matchesSelector, but doesn't work on orphaned elems
1217
+ // check for that
1218
+ var div = document.createElement('div');
1219
+ var supportsOrphans = match( div, 'div' );
1220
+ matchesSelector = supportsOrphans ? match : matchChild;
1221
+ } else {
1222
+ matchesSelector = query;
1223
+ }
1224
+
1225
+ // transport
1226
+ if ( typeof define === 'function' && define.amd ) {
1227
+ // AMD
1228
+ define( 'matches-selector/matches-selector',[],function() {
1229
+ return matchesSelector;
1230
+ });
1231
+ } else if ( typeof exports === 'object' ) {
1232
+ module.exports = matchesSelector;
1233
+ }
1234
+ else {
1235
+ // browser global
1236
+ window.matchesSelector = matchesSelector;
1237
+ }
1238
+
1239
+ })( Element.prototype );
1240
+
1241
+ /**
1242
+ * Outlayer Item
1243
+ */
1244
+
1245
+ ( function( window ) {
1246
+
1247
+
1248
+
1249
+ // ----- get style ----- //
1250
+
1251
+ var getComputedStyle = window.getComputedStyle;
1252
+ var getStyle = getComputedStyle ?
1253
+ function( elem ) {
1254
+ return getComputedStyle( elem, null );
1255
+ } :
1256
+ function( elem ) {
1257
+ return elem.currentStyle;
1258
+ };
1259
+
1260
+
1261
+ // extend objects
1262
+ function extend( a, b ) {
1263
+ for ( var prop in b ) {
1264
+ a[ prop ] = b[ prop ];
1265
+ }
1266
+ return a;
1267
+ }
1268
+
1269
+ function isEmptyObj( obj ) {
1270
+ for ( var prop in obj ) {
1271
+ return false;
1272
+ }
1273
+ prop = null;
1274
+ return true;
1275
+ }
1276
+
1277
+ // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
1278
+ function toDash( str ) {
1279
+ return str.replace( /([A-Z])/g, function( $1 ){
1280
+ return '-' + $1.toLowerCase();
1281
+ });
1282
+ }
1283
+
1284
+ // -------------------------- Outlayer definition -------------------------- //
1285
+
1286
+ function outlayerItemDefinition( EventEmitter, getSize, getStyleProperty ) {
1287
+
1288
+ // -------------------------- CSS3 support -------------------------- //
1289
+
1290
+ var transitionProperty = getStyleProperty('transition');
1291
+ var transformProperty = getStyleProperty('transform');
1292
+ var supportsCSS3 = transitionProperty && transformProperty;
1293
+ var is3d = !!getStyleProperty('perspective');
1294
+
1295
+ var transitionEndEvent = {
1296
+ WebkitTransition: 'webkitTransitionEnd',
1297
+ MozTransition: 'transitionend',
1298
+ OTransition: 'otransitionend',
1299
+ transition: 'transitionend'
1300
+ }[ transitionProperty ];
1301
+
1302
+ // properties that could have vendor prefix
1303
+ var prefixableProperties = [
1304
+ 'transform',
1305
+ 'transition',
1306
+ 'transitionDuration',
1307
+ 'transitionProperty'
1308
+ ];
1309
+
1310
+ // cache all vendor properties
1311
+ var vendorProperties = ( function() {
1312
+ var cache = {};
1313
+ for ( var i=0, len = prefixableProperties.length; i < len; i++ ) {
1314
+ var prop = prefixableProperties[i];
1315
+ var supportedProp = getStyleProperty( prop );
1316
+ if ( supportedProp && supportedProp !== prop ) {
1317
+ cache[ prop ] = supportedProp;
1318
+ }
1319
+ }
1320
+ return cache;
1321
+ })();
1322
+
1323
+ // -------------------------- Item -------------------------- //
1324
+
1325
+ function Item( element, layout ) {
1326
+ if ( !element ) {
1327
+ return;
1328
+ }
1329
+
1330
+ this.element = element;
1331
+ // parent layout class, i.e. Masonry, Isotope, or Packery
1332
+ this.layout = layout;
1333
+ this.position = {
1334
+ x: 0,
1335
+ y: 0
1336
+ };
1337
+
1338
+ this._create();
1339
+ }
1340
+
1341
+ // inherit EventEmitter
1342
+ extend( Item.prototype, EventEmitter.prototype );
1343
+
1344
+ Item.prototype._create = function() {
1345
+ // transition objects
1346
+ this._transn = {
1347
+ ingProperties: {},
1348
+ clean: {},
1349
+ onEnd: {}
1350
+ };
1351
+
1352
+ this.css({
1353
+ position: 'absolute'
1354
+ });
1355
+ };
1356
+
1357
+ // trigger specified handler for event type
1358
+ Item.prototype.handleEvent = function( event ) {
1359
+ var method = 'on' + event.type;
1360
+ if ( this[ method ] ) {
1361
+ this[ method ]( event );
1362
+ }
1363
+ };
1364
+
1365
+ Item.prototype.getSize = function() {
1366
+ this.size = getSize( this.element );
1367
+ };
1368
+
1369
+ /**
1370
+ * apply CSS styles to element
1371
+ * @param {Object} style
1372
+ */
1373
+ Item.prototype.css = function( style ) {
1374
+ var elemStyle = this.element.style;
1375
+
1376
+ for ( var prop in style ) {
1377
+ // use vendor property if available
1378
+ var supportedProp = vendorProperties[ prop ] || prop;
1379
+ elemStyle[ supportedProp ] = style[ prop ];
1380
+ }
1381
+ };
1382
+
1383
+ // measure position, and sets it
1384
+ Item.prototype.getPosition = function() {
1385
+ var style = getStyle( this.element );
1386
+ var layoutOptions = this.layout.options;
1387
+ var isOriginLeft = layoutOptions.isOriginLeft;
1388
+ var isOriginTop = layoutOptions.isOriginTop;
1389
+ var x = parseInt( style[ isOriginLeft ? 'left' : 'right' ], 10 );
1390
+ var y = parseInt( style[ isOriginTop ? 'top' : 'bottom' ], 10 );
1391
+
1392
+ // clean up 'auto' or other non-integer values
1393
+ x = isNaN( x ) ? 0 : x;
1394
+ y = isNaN( y ) ? 0 : y;
1395
+ // remove padding from measurement
1396
+ var layoutSize = this.layout.size;
1397
+ x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
1398
+ y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
1399
+
1400
+ this.position.x = x;
1401
+ this.position.y = y;
1402
+ };
1403
+
1404
+ // set settled position, apply padding
1405
+ Item.prototype.layoutPosition = function() {
1406
+ var layoutSize = this.layout.size;
1407
+ var layoutOptions = this.layout.options;
1408
+ var style = {};
1409
+
1410
+ if ( layoutOptions.isOriginLeft ) {
1411
+ style.left = ( this.position.x + layoutSize.paddingLeft ) + 'px';
1412
+ // reset other property
1413
+ style.right = '';
1414
+ } else {
1415
+ style.right = ( this.position.x + layoutSize.paddingRight ) + 'px';
1416
+ style.left = '';
1417
+ }
1418
+
1419
+ if ( layoutOptions.isOriginTop ) {
1420
+ style.top = ( this.position.y + layoutSize.paddingTop ) + 'px';
1421
+ style.bottom = '';
1422
+ } else {
1423
+ style.bottom = ( this.position.y + layoutSize.paddingBottom ) + 'px';
1424
+ style.top = '';
1425
+ }
1426
+
1427
+ this.css( style );
1428
+ this.emitEvent( 'layout', [ this ] );
1429
+ };
1430
+
1431
+
1432
+ // transform translate function
1433
+ var translate = is3d ?
1434
+ function( x, y ) {
1435
+ return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
1436
+ } :
1437
+ function( x, y ) {
1438
+ return 'translate(' + x + 'px, ' + y + 'px)';
1439
+ };
1440
+
1441
+
1442
+ Item.prototype._transitionTo = function( x, y ) {
1443
+ this.getPosition();
1444
+ // get current x & y from top/left
1445
+ var curX = this.position.x;
1446
+ var curY = this.position.y;
1447
+
1448
+ var compareX = parseInt( x, 10 );
1449
+ var compareY = parseInt( y, 10 );
1450
+ var didNotMove = compareX === this.position.x && compareY === this.position.y;
1451
+
1452
+ // save end position
1453
+ this.setPosition( x, y );
1454
+
1455
+ // if did not move and not transitioning, just go to layout
1456
+ if ( didNotMove && !this.isTransitioning ) {
1457
+ this.layoutPosition();
1458
+ return;
1459
+ }
1460
+
1461
+ var transX = x - curX;
1462
+ var transY = y - curY;
1463
+ var transitionStyle = {};
1464
+ // flip cooridinates if origin on right or bottom
1465
+ var layoutOptions = this.layout.options;
1466
+ transX = layoutOptions.isOriginLeft ? transX : -transX;
1467
+ transY = layoutOptions.isOriginTop ? transY : -transY;
1468
+ transitionStyle.transform = translate( transX, transY );
1469
+
1470
+ this.transition({
1471
+ to: transitionStyle,
1472
+ onTransitionEnd: {
1473
+ transform: this.layoutPosition
1474
+ },
1475
+ isCleaning: true
1476
+ });
1477
+ };
1478
+
1479
+ // non transition + transform support
1480
+ Item.prototype.goTo = function( x, y ) {
1481
+ this.setPosition( x, y );
1482
+ this.layoutPosition();
1483
+ };
1484
+
1485
+ // use transition and transforms if supported
1486
+ Item.prototype.moveTo = supportsCSS3 ?
1487
+ Item.prototype._transitionTo : Item.prototype.goTo;
1488
+
1489
+ Item.prototype.setPosition = function( x, y ) {
1490
+ this.position.x = parseInt( x, 10 );
1491
+ this.position.y = parseInt( y, 10 );
1492
+ };
1493
+
1494
+ // ----- transition ----- //
1495
+
1496
+ /**
1497
+ * @param {Object} style - CSS
1498
+ * @param {Function} onTransitionEnd
1499
+ */
1500
+
1501
+ // non transition, just trigger callback
1502
+ Item.prototype._nonTransition = function( args ) {
1503
+ this.css( args.to );
1504
+ if ( args.isCleaning ) {
1505
+ this._removeStyles( args.to );
1506
+ }
1507
+ for ( var prop in args.onTransitionEnd ) {
1508
+ args.onTransitionEnd[ prop ].call( this );
1509
+ }
1510
+ };
1511
+
1512
+ /**
1513
+ * proper transition
1514
+ * @param {Object} args - arguments
1515
+ * @param {Object} to - style to transition to
1516
+ * @param {Object} from - style to start transition from
1517
+ * @param {Boolean} isCleaning - removes transition styles after transition
1518
+ * @param {Function} onTransitionEnd - callback
1519
+ */
1520
+ Item.prototype._transition = function( args ) {
1521
+ // redirect to nonTransition if no transition duration
1522
+ if ( !parseFloat( this.layout.options.transitionDuration ) ) {
1523
+ this._nonTransition( args );
1524
+ return;
1525
+ }
1526
+
1527
+ var _transition = this._transn;
1528
+ // keep track of onTransitionEnd callback by css property
1529
+ for ( var prop in args.onTransitionEnd ) {
1530
+ _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
1531
+ }
1532
+ // keep track of properties that are transitioning
1533
+ for ( prop in args.to ) {
1534
+ _transition.ingProperties[ prop ] = true;
1535
+ // keep track of properties to clean up when transition is done
1536
+ if ( args.isCleaning ) {
1537
+ _transition.clean[ prop ] = true;
1538
+ }
1539
+ }
1540
+
1541
+ // set from styles
1542
+ if ( args.from ) {
1543
+ this.css( args.from );
1544
+ // force redraw. http://blog.alexmaccaw.com/css-transitions
1545
+ var h = this.element.offsetHeight;
1546
+ // hack for JSHint to hush about unused var
1547
+ h = null;
1548
+ }
1549
+ // enable transition
1550
+ this.enableTransition( args.to );
1551
+ // set styles that are transitioning
1552
+ this.css( args.to );
1553
+
1554
+ this.isTransitioning = true;
1555
+
1556
+ };
1557
+
1558
+ var itemTransitionProperties = transformProperty && ( toDash( transformProperty ) +
1559
+ ',opacity' );
1560
+
1561
+ Item.prototype.enableTransition = function(/* style */) {
1562
+ // only enable if not already transitioning
1563
+ // bug in IE10 were re-setting transition style will prevent
1564
+ // transitionend event from triggering
1565
+ if ( this.isTransitioning ) {
1566
+ return;
1567
+ }
1568
+
1569
+ // make transition: foo, bar, baz from style object
1570
+ // TODO uncomment this bit when IE10 bug is resolved
1571
+ // var transitionValue = [];
1572
+ // for ( var prop in style ) {
1573
+ // // dash-ify camelCased properties like WebkitTransition
1574
+ // transitionValue.push( toDash( prop ) );
1575
+ // }
1576
+ // enable transition styles
1577
+ // HACK always enable transform,opacity for IE10
1578
+ this.css({
1579
+ transitionProperty: itemTransitionProperties,
1580
+ transitionDuration: this.layout.options.transitionDuration
1581
+ });
1582
+ // listen for transition end event
1583
+ this.element.addEventListener( transitionEndEvent, this, false );
1584
+ };
1585
+
1586
+ Item.prototype.transition = Item.prototype[ transitionProperty ? '_transition' : '_nonTransition' ];
1587
+
1588
+ // ----- events ----- //
1589
+
1590
+ Item.prototype.onwebkitTransitionEnd = function( event ) {
1591
+ this.ontransitionend( event );
1592
+ };
1593
+
1594
+ Item.prototype.onotransitionend = function( event ) {
1595
+ this.ontransitionend( event );
1596
+ };
1597
+
1598
+ // properties that I munge to make my life easier
1599
+ var dashedVendorProperties = {
1600
+ '-webkit-transform': 'transform',
1601
+ '-moz-transform': 'transform',
1602
+ '-o-transform': 'transform'
1603
+ };
1604
+
1605
+ Item.prototype.ontransitionend = function( event ) {
1606
+ // disregard bubbled events from children
1607
+ if ( event.target !== this.element ) {
1608
+ return;
1609
+ }
1610
+ var _transition = this._transn;
1611
+ // get property name of transitioned property, convert to prefix-free
1612
+ var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
1613
+
1614
+ // remove property that has completed transitioning
1615
+ delete _transition.ingProperties[ propertyName ];
1616
+ // check if any properties are still transitioning
1617
+ if ( isEmptyObj( _transition.ingProperties ) ) {
1618
+ // all properties have completed transitioning
1619
+ this.disableTransition();
1620
+ }
1621
+ // clean style
1622
+ if ( propertyName in _transition.clean ) {
1623
+ // clean up style
1624
+ this.element.style[ event.propertyName ] = '';
1625
+ delete _transition.clean[ propertyName ];
1626
+ }
1627
+ // trigger onTransitionEnd callback
1628
+ if ( propertyName in _transition.onEnd ) {
1629
+ var onTransitionEnd = _transition.onEnd[ propertyName ];
1630
+ onTransitionEnd.call( this );
1631
+ delete _transition.onEnd[ propertyName ];
1632
+ }
1633
+
1634
+ this.emitEvent( 'transitionEnd', [ this ] );
1635
+ };
1636
+
1637
+ Item.prototype.disableTransition = function() {
1638
+ this.removeTransitionStyles();
1639
+ this.element.removeEventListener( transitionEndEvent, this, false );
1640
+ this.isTransitioning = false;
1641
+ };
1642
+
1643
+ /**
1644
+ * removes style property from element
1645
+ * @param {Object} style
1646
+ **/
1647
+ Item.prototype._removeStyles = function( style ) {
1648
+ // clean up transition styles
1649
+ var cleanStyle = {};
1650
+ for ( var prop in style ) {
1651
+ cleanStyle[ prop ] = '';
1652
+ }
1653
+ this.css( cleanStyle );
1654
+ };
1655
+
1656
+ var cleanTransitionStyle = {
1657
+ transitionProperty: '',
1658
+ transitionDuration: ''
1659
+ };
1660
+
1661
+ Item.prototype.removeTransitionStyles = function() {
1662
+ // remove transition
1663
+ this.css( cleanTransitionStyle );
1664
+ };
1665
+
1666
+ // ----- show/hide/remove ----- //
1667
+
1668
+ // remove element from DOM
1669
+ Item.prototype.removeElem = function() {
1670
+ this.element.parentNode.removeChild( this.element );
1671
+ this.emitEvent( 'remove', [ this ] );
1672
+ };
1673
+
1674
+ Item.prototype.remove = function() {
1675
+ // just remove element if no transition support or no transition
1676
+ if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
1677
+ this.removeElem();
1678
+ return;
1679
+ }
1680
+
1681
+ // start transition
1682
+ var _this = this;
1683
+ this.on( 'transitionEnd', function() {
1684
+ _this.removeElem();
1685
+ return true; // bind once
1686
+ });
1687
+ this.hide();
1688
+ };
1689
+
1690
+ Item.prototype.reveal = function() {
1691
+ delete this.isHidden;
1692
+ // remove display: none
1693
+ this.css({ display: '' });
1694
+
1695
+ var options = this.layout.options;
1696
+ this.transition({
1697
+ from: options.hiddenStyle,
1698
+ to: options.visibleStyle,
1699
+ isCleaning: true
1700
+ });
1701
+ };
1702
+
1703
+ Item.prototype.hide = function() {
1704
+ // set flag
1705
+ this.isHidden = true;
1706
+ // remove display: none
1707
+ this.css({ display: '' });
1708
+
1709
+ var options = this.layout.options;
1710
+ this.transition({
1711
+ from: options.visibleStyle,
1712
+ to: options.hiddenStyle,
1713
+ // keep hidden stuff hidden
1714
+ isCleaning: true,
1715
+ onTransitionEnd: {
1716
+ opacity: function() {
1717
+ // check if still hidden
1718
+ // during transition, item may have been un-hidden
1719
+ if ( this.isHidden ) {
1720
+ this.css({ display: 'none' });
1721
+ }
1722
+ }
1723
+ }
1724
+ });
1725
+ };
1726
+
1727
+ Item.prototype.destroy = function() {
1728
+ this.css({
1729
+ position: '',
1730
+ left: '',
1731
+ right: '',
1732
+ top: '',
1733
+ bottom: '',
1734
+ transition: '',
1735
+ transform: ''
1736
+ });
1737
+ };
1738
+
1739
+ return Item;
1740
+
1741
+ }
1742
+
1743
+ // -------------------------- transport -------------------------- //
1744
+
1745
+ if ( typeof define === 'function' && define.amd ) {
1746
+ // AMD
1747
+ define( 'outlayer/item',[
1748
+ 'eventEmitter/EventEmitter',
1749
+ 'get-size/get-size',
1750
+ 'get-style-property/get-style-property'
1751
+ ],
1752
+ outlayerItemDefinition );
1753
+ } else {
1754
+ // browser global
1755
+ window.Outlayer = {};
1756
+ window.Outlayer.Item = outlayerItemDefinition(
1757
+ window.EventEmitter,
1758
+ window.getSize,
1759
+ window.getStyleProperty
1760
+ );
1761
+ }
1762
+
1763
+ })( window );
1764
+
1765
+ /*!
1766
+ * Outlayer v1.2.0
1767
+ * the brains and guts of a layout library
1768
+ * MIT license
1769
+ */
1770
+
1771
+ ( function( window ) {
1772
+
1773
+
1774
+
1775
+ // ----- vars ----- //
1776
+
1777
+ var document = window.document;
1778
+ var console = window.console;
1779
+ var jQuery = window.jQuery;
1780
+
1781
+ var noop = function() {};
1782
+
1783
+ // -------------------------- helpers -------------------------- //
1784
+
1785
+ // extend objects
1786
+ function extend( a, b ) {
1787
+ for ( var prop in b ) {
1788
+ a[ prop ] = b[ prop ];
1789
+ }
1790
+ return a;
1791
+ }
1792
+
1793
+
1794
+ var objToString = Object.prototype.toString;
1795
+ function isArray( obj ) {
1796
+ return objToString.call( obj ) === '[object Array]';
1797
+ }
1798
+
1799
+ // turn element or nodeList into an array
1800
+ function makeArray( obj ) {
1801
+ var ary = [];
1802
+ if ( isArray( obj ) ) {
1803
+ // use object if already an array
1804
+ ary = obj;
1805
+ } else if ( obj && typeof obj.length === 'number' ) {
1806
+ // convert nodeList to array
1807
+ for ( var i=0, len = obj.length; i < len; i++ ) {
1808
+ ary.push( obj[i] );
1809
+ }
1810
+ } else {
1811
+ // array of single index
1812
+ ary.push( obj );
1813
+ }
1814
+ return ary;
1815
+ }
1816
+
1817
+ // http://stackoverflow.com/a/384380/182183
1818
+ var isElement = ( typeof HTMLElement === 'object' ) ?
1819
+ function isElementDOM2( obj ) {
1820
+ return obj instanceof HTMLElement;
1821
+ } :
1822
+ function isElementQuirky( obj ) {
1823
+ return obj && typeof obj === 'object' &&
1824
+ obj.nodeType === 1 && typeof obj.nodeName === 'string';
1825
+ };
1826
+
1827
+ // index of helper cause IE8
1828
+ var indexOf = Array.prototype.indexOf ? function( ary, obj ) {
1829
+ return ary.indexOf( obj );
1830
+ } : function( ary, obj ) {
1831
+ for ( var i=0, len = ary.length; i < len; i++ ) {
1832
+ if ( ary[i] === obj ) {
1833
+ return i;
1834
+ }
1835
+ }
1836
+ return -1;
1837
+ };
1838
+
1839
+ function removeFrom( obj, ary ) {
1840
+ var index = indexOf( ary, obj );
1841
+ if ( index !== -1 ) {
1842
+ ary.splice( index, 1 );
1843
+ }
1844
+ }
1845
+
1846
+ // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
1847
+ function toDashed( str ) {
1848
+ return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
1849
+ return $1 + '-' + $2;
1850
+ }).toLowerCase();
1851
+ }
1852
+
1853
+
1854
+ function outlayerDefinition( eventie, docReady, EventEmitter, getSize, matchesSelector, Item ) {
1855
+
1856
+ // -------------------------- Outlayer -------------------------- //
1857
+
1858
+ // globally unique identifiers
1859
+ var GUID = 0;
1860
+ // internal store of all Outlayer intances
1861
+ var instances = {};
1862
+
1863
+
1864
+ /**
1865
+ * @param {Element, String} element
1866
+ * @param {Object} options
1867
+ * @constructor
1868
+ */
1869
+ function Outlayer( element, options ) {
1870
+ // use element as selector string
1871
+ if ( typeof element === 'string' ) {
1872
+ element = document.querySelector( element );
1873
+ }
1874
+
1875
+ // bail out if not proper element
1876
+ if ( !element || !isElement( element ) ) {
1877
+ if ( console ) {
1878
+ console.error( 'Bad ' + this.constructor.namespace + ' element: ' + element );
1879
+ }
1880
+ return;
1881
+ }
1882
+
1883
+ this.element = element;
1884
+
1885
+ // options
1886
+ this.options = extend( {}, this.constructor.defaults );
1887
+ this.option( options );
1888
+
1889
+ // add id for Outlayer.getFromElement
1890
+ var id = ++GUID;
1891
+ this.element.outlayerGUID = id; // expando
1892
+ instances[ id ] = this; // associate via id
1893
+
1894
+ // kick it off
1895
+ this._create();
1896
+
1897
+ if ( this.options.isInitLayout ) {
1898
+ this.layout();
1899
+ }
1900
+ }
1901
+
1902
+ // settings are for internal use only
1903
+ Outlayer.namespace = 'outlayer';
1904
+ Outlayer.Item = Item;
1905
+
1906
+ // default options
1907
+ Outlayer.defaults = {
1908
+ containerStyle: {
1909
+ position: 'relative'
1910
+ },
1911
+ isInitLayout: true,
1912
+ isOriginLeft: true,
1913
+ isOriginTop: true,
1914
+ isResizeBound: true,
1915
+ isResizingContainer: true,
1916
+ // item options
1917
+ transitionDuration: '0.4s',
1918
+ hiddenStyle: {
1919
+ opacity: 0,
1920
+ transform: 'scale(0.001)'
1921
+ },
1922
+ visibleStyle: {
1923
+ opacity: 1,
1924
+ transform: 'scale(1)'
1925
+ }
1926
+ };
1927
+
1928
+ // inherit EventEmitter
1929
+ extend( Outlayer.prototype, EventEmitter.prototype );
1930
+
1931
+ /**
1932
+ * set options
1933
+ * @param {Object} opts
1934
+ */
1935
+ Outlayer.prototype.option = function( opts ) {
1936
+ extend( this.options, opts );
1937
+ };
1938
+
1939
+ Outlayer.prototype._create = function() {
1940
+ // get items from children
1941
+ this.reloadItems();
1942
+ // elements that affect layout, but are not laid out
1943
+ this.stamps = [];
1944
+ this.stamp( this.options.stamp );
1945
+ // set container style
1946
+ extend( this.element.style, this.options.containerStyle );
1947
+
1948
+ // bind resize method
1949
+ if ( this.options.isResizeBound ) {
1950
+ this.bindResize();
1951
+ }
1952
+ };
1953
+
1954
+ // goes through all children again and gets bricks in proper order
1955
+ Outlayer.prototype.reloadItems = function() {
1956
+ // collection of item elements
1957
+ this.items = this._itemize( this.element.children );
1958
+ };
1959
+
1960
+
1961
+ /**
1962
+ * turn elements into Outlayer.Items to be used in layout
1963
+ * @param {Array or NodeList or HTMLElement} elems
1964
+ * @returns {Array} items - collection of new Outlayer Items
1965
+ */
1966
+ Outlayer.prototype._itemize = function( elems ) {
1967
+
1968
+ var itemElems = this._filterFindItemElements( elems );
1969
+ var Item = this.constructor.Item;
1970
+
1971
+ // create new Outlayer Items for collection
1972
+ var items = [];
1973
+ for ( var i=0, len = itemElems.length; i < len; i++ ) {
1974
+ var elem = itemElems[i];
1975
+ var item = new Item( elem, this );
1976
+ items.push( item );
1977
+ }
1978
+
1979
+ return items;
1980
+ };
1981
+
1982
+ /**
1983
+ * get item elements to be used in layout
1984
+ * @param {Array or NodeList or HTMLElement} elems
1985
+ * @returns {Array} items - item elements
1986
+ */
1987
+ Outlayer.prototype._filterFindItemElements = function( elems ) {
1988
+ // make array of elems
1989
+ elems = makeArray( elems );
1990
+ var itemSelector = this.options.itemSelector;
1991
+ var itemElems = [];
1992
+
1993
+ for ( var i=0, len = elems.length; i < len; i++ ) {
1994
+ var elem = elems[i];
1995
+ // check that elem is an actual element
1996
+ if ( !isElement( elem ) ) {
1997
+ continue;
1998
+ }
1999
+ // filter & find items if we have an item selector
2000
+ if ( itemSelector ) {
2001
+ // filter siblings
2002
+ if ( matchesSelector( elem, itemSelector ) ) {
2003
+ itemElems.push( elem );
2004
+ }
2005
+ // find children
2006
+ var childElems = elem.querySelectorAll( itemSelector );
2007
+ // concat childElems to filterFound array
2008
+ for ( var j=0, jLen = childElems.length; j < jLen; j++ ) {
2009
+ itemElems.push( childElems[j] );
2010
+ }
2011
+ } else {
2012
+ itemElems.push( elem );
2013
+ }
2014
+ }
2015
+
2016
+ return itemElems;
2017
+ };
2018
+
2019
+ /**
2020
+ * getter method for getting item elements
2021
+ * @returns {Array} elems - collection of item elements
2022
+ */
2023
+ Outlayer.prototype.getItemElements = function() {
2024
+ var elems = [];
2025
+ for ( var i=0, len = this.items.length; i < len; i++ ) {
2026
+ elems.push( this.items[i].element );
2027
+ }
2028
+ return elems;
2029
+ };
2030
+
2031
+ // ----- init & layout ----- //
2032
+
2033
+ /**
2034
+ * lays out all items
2035
+ */
2036
+ Outlayer.prototype.layout = function() {
2037
+ this._resetLayout();
2038
+ this._manageStamps();
2039
+
2040
+ // don't animate first layout
2041
+ var isInstant = this.options.isLayoutInstant !== undefined ?
2042
+ this.options.isLayoutInstant : !this._isLayoutInited;
2043
+ this.layoutItems( this.items, isInstant );
2044
+
2045
+ // flag for initalized
2046
+ this._isLayoutInited = true;
2047
+ };
2048
+
2049
+ // _init is alias for layout
2050
+ Outlayer.prototype._init = Outlayer.prototype.layout;
2051
+
2052
+ /**
2053
+ * logic before any new layout
2054
+ */
2055
+ Outlayer.prototype._resetLayout = function() {
2056
+ this.getSize();
2057
+ };
2058
+
2059
+
2060
+ Outlayer.prototype.getSize = function() {
2061
+ this.size = getSize( this.element );
2062
+ };
2063
+
2064
+ /**
2065
+ * get measurement from option, for columnWidth, rowHeight, gutter
2066
+ * if option is String -> get element from selector string, & get size of element
2067
+ * if option is Element -> get size of element
2068
+ * else use option as a number
2069
+ *
2070
+ * @param {String} measurement
2071
+ * @param {String} size - width or height
2072
+ * @private
2073
+ */
2074
+ Outlayer.prototype._getMeasurement = function( measurement, size ) {
2075
+ var option = this.options[ measurement ];
2076
+ var elem;
2077
+ if ( !option ) {
2078
+ // default to 0
2079
+ this[ measurement ] = 0;
2080
+ } else {
2081
+ // use option as an element
2082
+ if ( typeof option === 'string' ) {
2083
+ elem = this.element.querySelector( option );
2084
+ } else if ( isElement( option ) ) {
2085
+ elem = option;
2086
+ }
2087
+ // use size of element, if element
2088
+ this[ measurement ] = elem ? getSize( elem )[ size ] : option;
2089
+ }
2090
+ };
2091
+
2092
+ /**
2093
+ * layout a collection of item elements
2094
+ * @api public
2095
+ */
2096
+ Outlayer.prototype.layoutItems = function( items, isInstant ) {
2097
+ items = this._getItemsForLayout( items );
2098
+
2099
+ this._layoutItems( items, isInstant );
2100
+
2101
+ this._postLayout();
2102
+ };
2103
+
2104
+ /**
2105
+ * get the items to be laid out
2106
+ * you may want to skip over some items
2107
+ * @param {Array} items
2108
+ * @returns {Array} items
2109
+ */
2110
+ Outlayer.prototype._getItemsForLayout = function( items ) {
2111
+ var layoutItems = [];
2112
+ for ( var i=0, len = items.length; i < len; i++ ) {
2113
+ var item = items[i];
2114
+ if ( !item.isIgnored ) {
2115
+ layoutItems.push( item );
2116
+ }
2117
+ }
2118
+ return layoutItems;
2119
+ };
2120
+
2121
+ /**
2122
+ * layout items
2123
+ * @param {Array} items
2124
+ * @param {Boolean} isInstant
2125
+ */
2126
+ Outlayer.prototype._layoutItems = function( items, isInstant ) {
2127
+ var _this = this;
2128
+ function onItemsLayout() {
2129
+ _this.emitEvent( 'layoutComplete', [ _this, items ] );
2130
+ }
2131
+
2132
+ if ( !items || !items.length ) {
2133
+ // no items, emit event with empty array
2134
+ onItemsLayout();
2135
+ return;
2136
+ }
2137
+
2138
+ // emit layoutComplete when done
2139
+ this._itemsOn( items, 'layout', onItemsLayout );
2140
+
2141
+ var queue = [];
2142
+
2143
+ for ( var i=0, len = items.length; i < len; i++ ) {
2144
+ var item = items[i];
2145
+ // get x/y object from method
2146
+ var position = this._getItemLayoutPosition( item );
2147
+ // enqueue
2148
+ position.item = item;
2149
+ position.isInstant = isInstant || item.isLayoutInstant;
2150
+ queue.push( position );
2151
+ }
2152
+
2153
+ this._processLayoutQueue( queue );
2154
+ };
2155
+
2156
+ /**
2157
+ * get item layout position
2158
+ * @param {Outlayer.Item} item
2159
+ * @returns {Object} x and y position
2160
+ */
2161
+ Outlayer.prototype._getItemLayoutPosition = function( /* item */ ) {
2162
+ return {
2163
+ x: 0,
2164
+ y: 0
2165
+ };
2166
+ };
2167
+
2168
+ /**
2169
+ * iterate over array and position each item
2170
+ * Reason being - separating this logic prevents 'layout invalidation'
2171
+ * thx @paul_irish
2172
+ * @param {Array} queue
2173
+ */
2174
+ Outlayer.prototype._processLayoutQueue = function( queue ) {
2175
+ for ( var i=0, len = queue.length; i < len; i++ ) {
2176
+ var obj = queue[i];
2177
+ this._positionItem( obj.item, obj.x, obj.y, obj.isInstant );
2178
+ }
2179
+ };
2180
+
2181
+ /**
2182
+ * Sets position of item in DOM
2183
+ * @param {Outlayer.Item} item
2184
+ * @param {Number} x - horizontal position
2185
+ * @param {Number} y - vertical position
2186
+ * @param {Boolean} isInstant - disables transitions
2187
+ */
2188
+ Outlayer.prototype._positionItem = function( item, x, y, isInstant ) {
2189
+ if ( isInstant ) {
2190
+ // if not transition, just set CSS
2191
+ item.goTo( x, y );
2192
+ } else {
2193
+ item.moveTo( x, y );
2194
+ }
2195
+ };
2196
+
2197
+ /**
2198
+ * Any logic you want to do after each layout,
2199
+ * i.e. size the container
2200
+ */
2201
+ Outlayer.prototype._postLayout = function() {
2202
+ this.resizeContainer();
2203
+ };
2204
+
2205
+ Outlayer.prototype.resizeContainer = function() {
2206
+ if ( !this.options.isResizingContainer ) {
2207
+ return;
2208
+ }
2209
+ var size = this._getContainerSize();
2210
+ if ( size ) {
2211
+ this._setContainerMeasure( size.width, true );
2212
+ this._setContainerMeasure( size.height, false );
2213
+ }
2214
+ };
2215
+
2216
+ /**
2217
+ * Sets width or height of container if returned
2218
+ * @returns {Object} size
2219
+ * @param {Number} width
2220
+ * @param {Number} height
2221
+ */
2222
+ Outlayer.prototype._getContainerSize = noop;
2223
+
2224
+ /**
2225
+ * @param {Number} measure - size of width or height
2226
+ * @param {Boolean} isWidth
2227
+ */
2228
+ Outlayer.prototype._setContainerMeasure = function( measure, isWidth ) {
2229
+ if ( measure === undefined ) {
2230
+ return;
2231
+ }
2232
+
2233
+ var elemSize = this.size;
2234
+ // add padding and border width if border box
2235
+ if ( elemSize.isBorderBox ) {
2236
+ measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
2237
+ elemSize.borderLeftWidth + elemSize.borderRightWidth :
2238
+ elemSize.paddingBottom + elemSize.paddingTop +
2239
+ elemSize.borderTopWidth + elemSize.borderBottomWidth;
2240
+ }
2241
+
2242
+ measure = Math.max( measure, 0 );
2243
+ this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
2244
+ };
2245
+
2246
+ /**
2247
+ * trigger a callback for a collection of items events
2248
+ * @param {Array} items - Outlayer.Items
2249
+ * @param {String} eventName
2250
+ * @param {Function} callback
2251
+ */
2252
+ Outlayer.prototype._itemsOn = function( items, eventName, callback ) {
2253
+ var doneCount = 0;
2254
+ var count = items.length;
2255
+ // event callback
2256
+ var _this = this;
2257
+ function tick() {
2258
+ doneCount++;
2259
+ if ( doneCount === count ) {
2260
+ callback.call( _this );
2261
+ }
2262
+ return true; // bind once
2263
+ }
2264
+ // bind callback
2265
+ for ( var i=0, len = items.length; i < len; i++ ) {
2266
+ var item = items[i];
2267
+ item.on( eventName, tick );
2268
+ }
2269
+ };
2270
+
2271
+ // -------------------------- ignore & stamps -------------------------- //
2272
+
2273
+
2274
+ /**
2275
+ * keep item in collection, but do not lay it out
2276
+ * ignored items do not get skipped in layout
2277
+ * @param {Element} elem
2278
+ */
2279
+ Outlayer.prototype.ignore = function( elem ) {
2280
+ var item = this.getItem( elem );
2281
+ if ( item ) {
2282
+ item.isIgnored = true;
2283
+ }
2284
+ };
2285
+
2286
+ /**
2287
+ * return item to layout collection
2288
+ * @param {Element} elem
2289
+ */
2290
+ Outlayer.prototype.unignore = function( elem ) {
2291
+ var item = this.getItem( elem );
2292
+ if ( item ) {
2293
+ delete item.isIgnored;
2294
+ }
2295
+ };
2296
+
2297
+ /**
2298
+ * adds elements to stamps
2299
+ * @param {NodeList, Array, Element, or String} elems
2300
+ */
2301
+ Outlayer.prototype.stamp = function( elems ) {
2302
+ elems = this._find( elems );
2303
+ if ( !elems ) {
2304
+ return;
2305
+ }
2306
+
2307
+ this.stamps = this.stamps.concat( elems );
2308
+ // ignore
2309
+ for ( var i=0, len = elems.length; i < len; i++ ) {
2310
+ var elem = elems[i];
2311
+ this.ignore( elem );
2312
+ }
2313
+ };
2314
+
2315
+ /**
2316
+ * removes elements to stamps
2317
+ * @param {NodeList, Array, or Element} elems
2318
+ */
2319
+ Outlayer.prototype.unstamp = function( elems ) {
2320
+ elems = this._find( elems );
2321
+ if ( !elems ){
2322
+ return;
2323
+ }
2324
+
2325
+ for ( var i=0, len = elems.length; i < len; i++ ) {
2326
+ var elem = elems[i];
2327
+ // filter out removed stamp elements
2328
+ removeFrom( elem, this.stamps );
2329
+ this.unignore( elem );
2330
+ }
2331
+
2332
+ };
2333
+
2334
+ /**
2335
+ * finds child elements
2336
+ * @param {NodeList, Array, Element, or String} elems
2337
+ * @returns {Array} elems
2338
+ */
2339
+ Outlayer.prototype._find = function( elems ) {
2340
+ if ( !elems ) {
2341
+ return;
2342
+ }
2343
+ // if string, use argument as selector string
2344
+ if ( typeof elems === 'string' ) {
2345
+ elems = this.element.querySelectorAll( elems );
2346
+ }
2347
+ elems = makeArray( elems );
2348
+ return elems;
2349
+ };
2350
+
2351
+ Outlayer.prototype._manageStamps = function() {
2352
+ if ( !this.stamps || !this.stamps.length ) {
2353
+ return;
2354
+ }
2355
+
2356
+ this._getBoundingRect();
2357
+
2358
+ for ( var i=0, len = this.stamps.length; i < len; i++ ) {
2359
+ var stamp = this.stamps[i];
2360
+ this._manageStamp( stamp );
2361
+ }
2362
+ };
2363
+
2364
+ // update boundingLeft / Top
2365
+ Outlayer.prototype._getBoundingRect = function() {
2366
+ // get bounding rect for container element
2367
+ var boundingRect = this.element.getBoundingClientRect();
2368
+ var size = this.size;
2369
+ this._boundingRect = {
2370
+ left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
2371
+ top: boundingRect.top + size.paddingTop + size.borderTopWidth,
2372
+ right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
2373
+ bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
2374
+ };
2375
+ };
2376
+
2377
+ /**
2378
+ * @param {Element} stamp
2379
+ **/
2380
+ Outlayer.prototype._manageStamp = noop;
2381
+
2382
+ /**
2383
+ * get x/y position of element relative to container element
2384
+ * @param {Element} elem
2385
+ * @returns {Object} offset - has left, top, right, bottom
2386
+ */
2387
+ Outlayer.prototype._getElementOffset = function( elem ) {
2388
+ var boundingRect = elem.getBoundingClientRect();
2389
+ var thisRect = this._boundingRect;
2390
+ var size = getSize( elem );
2391
+ var offset = {
2392
+ left: boundingRect.left - thisRect.left - size.marginLeft,
2393
+ top: boundingRect.top - thisRect.top - size.marginTop,
2394
+ right: thisRect.right - boundingRect.right - size.marginRight,
2395
+ bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
2396
+ };
2397
+ return offset;
2398
+ };
2399
+
2400
+ // -------------------------- resize -------------------------- //
2401
+
2402
+ // enable event handlers for listeners
2403
+ // i.e. resize -> onresize
2404
+ Outlayer.prototype.handleEvent = function( event ) {
2405
+ var method = 'on' + event.type;
2406
+ if ( this[ method ] ) {
2407
+ this[ method ]( event );
2408
+ }
2409
+ };
2410
+
2411
+ /**
2412
+ * Bind layout to window resizing
2413
+ */
2414
+ Outlayer.prototype.bindResize = function() {
2415
+ // bind just one listener
2416
+ if ( this.isResizeBound ) {
2417
+ return;
2418
+ }
2419
+ eventie.bind( window, 'resize', this );
2420
+ this.isResizeBound = true;
2421
+ };
2422
+
2423
+ /**
2424
+ * Unbind layout to window resizing
2425
+ */
2426
+ Outlayer.prototype.unbindResize = function() {
2427
+ if ( this.isResizeBound ) {
2428
+ eventie.unbind( window, 'resize', this );
2429
+ }
2430
+ this.isResizeBound = false;
2431
+ };
2432
+
2433
+ // original debounce by John Hann
2434
+ // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
2435
+
2436
+ // this fires every resize
2437
+ Outlayer.prototype.onresize = function() {
2438
+ if ( this.resizeTimeout ) {
2439
+ clearTimeout( this.resizeTimeout );
2440
+ }
2441
+
2442
+ var _this = this;
2443
+ function delayed() {
2444
+ _this.resize();
2445
+ delete _this.resizeTimeout;
2446
+ }
2447
+
2448
+ this.resizeTimeout = setTimeout( delayed, 100 );
2449
+ };
2450
+
2451
+ // debounced, layout on resize
2452
+ Outlayer.prototype.resize = function() {
2453
+ // don't trigger if size did not change
2454
+ // or if resize was unbound. See #9
2455
+ if ( !this.isResizeBound || !this.needsResizeLayout() ) {
2456
+ return;
2457
+ }
2458
+
2459
+ this.layout();
2460
+ };
2461
+
2462
+ /**
2463
+ * check if layout is needed post layout
2464
+ * @returns Boolean
2465
+ */
2466
+ Outlayer.prototype.needsResizeLayout = function() {
2467
+ var size = getSize( this.element );
2468
+ // check that this.size and size are there
2469
+ // IE8 triggers resize on body size change, so they might not be
2470
+ var hasSizes = this.size && size;
2471
+ return hasSizes && size.innerWidth !== this.size.innerWidth;
2472
+ };
2473
+
2474
+ // -------------------------- methods -------------------------- //
2475
+
2476
+ /**
2477
+ * add items to Outlayer instance
2478
+ * @param {Array or NodeList or Element} elems
2479
+ * @returns {Array} items - Outlayer.Items
2480
+ **/
2481
+ Outlayer.prototype.addItems = function( elems ) {
2482
+ var items = this._itemize( elems );
2483
+ // add items to collection
2484
+ if ( items.length ) {
2485
+ this.items = this.items.concat( items );
2486
+ }
2487
+ return items;
2488
+ };
2489
+
2490
+ /**
2491
+ * Layout newly-appended item elements
2492
+ * @param {Array or NodeList or Element} elems
2493
+ */
2494
+ Outlayer.prototype.appended = function( elems ) {
2495
+ var items = this.addItems( elems );
2496
+ if ( !items.length ) {
2497
+ return;
2498
+ }
2499
+ // layout and reveal just the new items
2500
+ this.layoutItems( items, true );
2501
+ this.reveal( items );
2502
+ };
2503
+
2504
+ /**
2505
+ * Layout prepended elements
2506
+ * @param {Array or NodeList or Element} elems
2507
+ */
2508
+ Outlayer.prototype.prepended = function( elems ) {
2509
+ var items = this._itemize( elems );
2510
+ if ( !items.length ) {
2511
+ return;
2512
+ }
2513
+ // add items to beginning of collection
2514
+ var previousItems = this.items.slice(0);
2515
+ this.items = items.concat( previousItems );
2516
+ // start new layout
2517
+ this._resetLayout();
2518
+ this._manageStamps();
2519
+ // layout new stuff without transition
2520
+ this.layoutItems( items, true );
2521
+ this.reveal( items );
2522
+ // layout previous items
2523
+ this.layoutItems( previousItems );
2524
+ };
2525
+
2526
+ /**
2527
+ * reveal a collection of items
2528
+ * @param {Array of Outlayer.Items} items
2529
+ */
2530
+ Outlayer.prototype.reveal = function( items ) {
2531
+ var len = items && items.length;
2532
+ if ( !len ) {
2533
+ return;
2534
+ }
2535
+ for ( var i=0; i < len; i++ ) {
2536
+ var item = items[i];
2537
+ item.reveal();
2538
+ }
2539
+ };
2540
+
2541
+ /**
2542
+ * hide a collection of items
2543
+ * @param {Array of Outlayer.Items} items
2544
+ */
2545
+ Outlayer.prototype.hide = function( items ) {
2546
+ var len = items && items.length;
2547
+ if ( !len ) {
2548
+ return;
2549
+ }
2550
+ for ( var i=0; i < len; i++ ) {
2551
+ var item = items[i];
2552
+ item.hide();
2553
+ }
2554
+ };
2555
+
2556
+ /**
2557
+ * get Outlayer.Item, given an Element
2558
+ * @param {Element} elem
2559
+ * @param {Function} callback
2560
+ * @returns {Outlayer.Item} item
2561
+ */
2562
+ Outlayer.prototype.getItem = function( elem ) {
2563
+ // loop through items to get the one that matches
2564
+ for ( var i=0, len = this.items.length; i < len; i++ ) {
2565
+ var item = this.items[i];
2566
+ if ( item.element === elem ) {
2567
+ // return item
2568
+ return item;
2569
+ }
2570
+ }
2571
+ };
2572
+
2573
+ /**
2574
+ * get collection of Outlayer.Items, given Elements
2575
+ * @param {Array} elems
2576
+ * @returns {Array} items - Outlayer.Items
2577
+ */
2578
+ Outlayer.prototype.getItems = function( elems ) {
2579
+ if ( !elems || !elems.length ) {
2580
+ return;
2581
+ }
2582
+ var items = [];
2583
+ for ( var i=0, len = elems.length; i < len; i++ ) {
2584
+ var elem = elems[i];
2585
+ var item = this.getItem( elem );
2586
+ if ( item ) {
2587
+ items.push( item );
2588
+ }
2589
+ }
2590
+
2591
+ return items;
2592
+ };
2593
+
2594
+ /**
2595
+ * remove element(s) from instance and DOM
2596
+ * @param {Array or NodeList or Element} elems
2597
+ */
2598
+ Outlayer.prototype.remove = function( elems ) {
2599
+ elems = makeArray( elems );
2600
+
2601
+ var removeItems = this.getItems( elems );
2602
+ // bail if no items to remove
2603
+ if ( !removeItems || !removeItems.length ) {
2604
+ return;
2605
+ }
2606
+
2607
+ this._itemsOn( removeItems, 'remove', function() {
2608
+ this.emitEvent( 'removeComplete', [ this, removeItems ] );
2609
+ });
2610
+
2611
+ for ( var i=0, len = removeItems.length; i < len; i++ ) {
2612
+ var item = removeItems[i];
2613
+ item.remove();
2614
+ // remove item from collection
2615
+ removeFrom( item, this.items );
2616
+ }
2617
+ };
2618
+
2619
+ // ----- destroy ----- //
2620
+
2621
+ // remove and disable Outlayer instance
2622
+ Outlayer.prototype.destroy = function() {
2623
+ // clean up dynamic styles
2624
+ var style = this.element.style;
2625
+ style.height = '';
2626
+ style.position = '';
2627
+ style.width = '';
2628
+ // destroy items
2629
+ for ( var i=0, len = this.items.length; i < len; i++ ) {
2630
+ var item = this.items[i];
2631
+ item.destroy();
2632
+ }
2633
+
2634
+ this.unbindResize();
2635
+
2636
+ delete this.element.outlayerGUID;
2637
+ // remove data for jQuery
2638
+ if ( jQuery ) {
2639
+ jQuery.removeData( this.element, this.constructor.namespace );
2640
+ }
2641
+
2642
+ };
2643
+
2644
+ // -------------------------- data -------------------------- //
2645
+
2646
+ /**
2647
+ * get Outlayer instance from element
2648
+ * @param {Element} elem
2649
+ * @returns {Outlayer}
2650
+ */
2651
+ Outlayer.data = function( elem ) {
2652
+ var id = elem && elem.outlayerGUID;
2653
+ return id && instances[ id ];
2654
+ };
2655
+
2656
+
2657
+ // -------------------------- create Outlayer class -------------------------- //
2658
+
2659
+ /**
2660
+ * create a layout class
2661
+ * @param {String} namespace
2662
+ */
2663
+ Outlayer.create = function( namespace, options ) {
2664
+ // sub-class Outlayer
2665
+ function Layout() {
2666
+ Outlayer.apply( this, arguments );
2667
+ }
2668
+ // inherit Outlayer prototype, use Object.create if there
2669
+ if ( Object.create ) {
2670
+ Layout.prototype = Object.create( Outlayer.prototype );
2671
+ } else {
2672
+ extend( Layout.prototype, Outlayer.prototype );
2673
+ }
2674
+ // set contructor, used for namespace and Item
2675
+ Layout.prototype.constructor = Layout;
2676
+
2677
+ Layout.defaults = extend( {}, Outlayer.defaults );
2678
+ // apply new options
2679
+ extend( Layout.defaults, options );
2680
+ // keep prototype.settings for backwards compatibility (Packery v1.2.0)
2681
+ Layout.prototype.settings = {};
2682
+
2683
+ Layout.namespace = namespace;
2684
+
2685
+ Layout.data = Outlayer.data;
2686
+
2687
+ // sub-class Item
2688
+ Layout.Item = function LayoutItem() {
2689
+ Item.apply( this, arguments );
2690
+ };
2691
+
2692
+ Layout.Item.prototype = new Item();
2693
+
2694
+ // -------------------------- declarative -------------------------- //
2695
+
2696
+ /**
2697
+ * allow user to initialize Outlayer via .js-namespace class
2698
+ * options are parsed from data-namespace-option attribute
2699
+ */
2700
+ docReady( function() {
2701
+ var dashedNamespace = toDashed( namespace );
2702
+ var elems = document.querySelectorAll( '.js-' + dashedNamespace );
2703
+ var dataAttr = 'data-' + dashedNamespace + '-options';
2704
+
2705
+ for ( var i=0, len = elems.length; i < len; i++ ) {
2706
+ var elem = elems[i];
2707
+ var attr = elem.getAttribute( dataAttr );
2708
+ var options;
2709
+ try {
2710
+ options = attr && JSON.parse( attr );
2711
+ } catch ( error ) {
2712
+ // log error, do not initialize
2713
+ if ( console ) {
2714
+ console.error( 'Error parsing ' + dataAttr + ' on ' +
2715
+ elem.nodeName.toLowerCase() + ( elem.id ? '#' + elem.id : '' ) + ': ' +
2716
+ error );
2717
+ }
2718
+ continue;
2719
+ }
2720
+ // initialize
2721
+ var instance = new Layout( elem, options );
2722
+ // make available via $().data('layoutname')
2723
+ if ( jQuery ) {
2724
+ jQuery.data( elem, namespace, instance );
2725
+ }
2726
+ }
2727
+ });
2728
+
2729
+ // -------------------------- jQuery bridge -------------------------- //
2730
+
2731
+ // make into jQuery plugin
2732
+ if ( jQuery && jQuery.bridget ) {
2733
+ jQuery.bridget( namespace, Layout );
2734
+ }
2735
+
2736
+ return Layout;
2737
+ };
2738
+
2739
+ // ----- fin ----- //
2740
+
2741
+ // back in global
2742
+ Outlayer.Item = Item;
2743
+
2744
+ return Outlayer;
2745
+
2746
+ }
2747
+
2748
+ // -------------------------- transport -------------------------- //
2749
+
2750
+ if ( typeof define === 'function' && define.amd ) {
2751
+ // AMD
2752
+ define( 'outlayer/outlayer',[
2753
+ 'eventie/eventie',
2754
+ 'doc-ready/doc-ready',
2755
+ 'eventEmitter/EventEmitter',
2756
+ 'get-size/get-size',
2757
+ 'matches-selector/matches-selector',
2758
+ './item'
2759
+ ],
2760
+ outlayerDefinition );
2761
+ } else {
2762
+ // browser global
2763
+ window.Outlayer = outlayerDefinition(
2764
+ window.eventie,
2765
+ window.docReady,
2766
+ window.EventEmitter,
2767
+ window.getSize,
2768
+ window.matchesSelector,
2769
+ window.Outlayer.Item
2770
+ );
2771
+ }
2772
+
2773
+ })( window );
2774
+
2775
+ /**
2776
+ * Rect
2777
+ * low-level utility class for basic geometry
2778
+ */
2779
+
2780
+ ( function( window ) {
2781
+
2782
+
2783
+
2784
+ // -------------------------- Packery -------------------------- //
2785
+
2786
+ // global namespace
2787
+ var Packery = window.Packery = function() {};
2788
+
2789
+ function rectDefinition() {
2790
+
2791
+ // -------------------------- Rect -------------------------- //
2792
+
2793
+ function Rect( props ) {
2794
+ // extend properties from defaults
2795
+ for ( var prop in Rect.defaults ) {
2796
+ this[ prop ] = Rect.defaults[ prop ];
2797
+ }
2798
+
2799
+ for ( prop in props ) {
2800
+ this[ prop ] = props[ prop ];
2801
+ }
2802
+
2803
+ }
2804
+
2805
+ // make available
2806
+ Packery.Rect = Rect;
2807
+
2808
+ Rect.defaults = {
2809
+ x: 0,
2810
+ y: 0,
2811
+ width: 0,
2812
+ height: 0
2813
+ };
2814
+
2815
+ /**
2816
+ * Determines whether or not this rectangle wholly encloses another rectangle or point.
2817
+ * @param {Rect} rect
2818
+ * @returns {Boolean}
2819
+ **/
2820
+ Rect.prototype.contains = function( rect ) {
2821
+ // points don't have width or height
2822
+ var otherWidth = rect.width || 0;
2823
+ var otherHeight = rect.height || 0;
2824
+ return this.x <= rect.x &&
2825
+ this.y <= rect.y &&
2826
+ this.x + this.width >= rect.x + otherWidth &&
2827
+ this.y + this.height >= rect.y + otherHeight;
2828
+ };
2829
+
2830
+ /**
2831
+ * Determines whether or not the rectangle intersects with another.
2832
+ * @param {Rect} rect
2833
+ * @returns {Boolean}
2834
+ **/
2835
+ Rect.prototype.overlaps = function( rect ) {
2836
+ var thisRight = this.x + this.width;
2837
+ var thisBottom = this.y + this.height;
2838
+ var rectRight = rect.x + rect.width;
2839
+ var rectBottom = rect.y + rect.height;
2840
+
2841
+ // http://stackoverflow.com/a/306332
2842
+ return this.x < rectRight &&
2843
+ thisRight > rect.x &&
2844
+ this.y < rectBottom &&
2845
+ thisBottom > rect.y;
2846
+ };
2847
+
2848
+ /**
2849
+ * @param {Rect} rect - the overlapping rect
2850
+ * @returns {Array} freeRects - rects representing the area around the rect
2851
+ **/
2852
+ Rect.prototype.getMaximalFreeRects = function( rect ) {
2853
+
2854
+ // if no intersection, return false
2855
+ if ( !this.overlaps( rect ) ) {
2856
+ return false;
2857
+ }
2858
+
2859
+ var freeRects = [];
2860
+ var freeRect;
2861
+
2862
+ var thisRight = this.x + this.width;
2863
+ var thisBottom = this.y + this.height;
2864
+ var rectRight = rect.x + rect.width;
2865
+ var rectBottom = rect.y + rect.height;
2866
+
2867
+ // top
2868
+ if ( this.y < rect.y ) {
2869
+ freeRect = new Rect({
2870
+ x: this.x,
2871
+ y: this.y,
2872
+ width: this.width,
2873
+ height: rect.y - this.y
2874
+ });
2875
+ freeRects.push( freeRect );
2876
+ }
2877
+
2878
+ // right
2879
+ if ( thisRight > rectRight ) {
2880
+ freeRect = new Rect({
2881
+ x: rectRight,
2882
+ y: this.y,
2883
+ width: thisRight - rectRight,
2884
+ height: this.height
2885
+ });
2886
+ freeRects.push( freeRect );
2887
+ }
2888
+
2889
+ // bottom
2890
+ if ( thisBottom > rectBottom ) {
2891
+ freeRect = new Rect({
2892
+ x: this.x,
2893
+ y: rectBottom,
2894
+ width: this.width,
2895
+ height: thisBottom - rectBottom
2896
+ });
2897
+ freeRects.push( freeRect );
2898
+ }
2899
+
2900
+ // left
2901
+ if ( this.x < rect.x ) {
2902
+ freeRect = new Rect({
2903
+ x: this.x,
2904
+ y: this.y,
2905
+ width: rect.x - this.x,
2906
+ height: this.height
2907
+ });
2908
+ freeRects.push( freeRect );
2909
+ }
2910
+
2911
+ return freeRects;
2912
+ };
2913
+
2914
+ Rect.prototype.canFit = function( rect ) {
2915
+ return this.width >= rect.width && this.height >= rect.height;
2916
+ };
2917
+
2918
+ return Rect;
2919
+
2920
+ }
2921
+
2922
+ // -------------------------- transport -------------------------- //
2923
+
2924
+ if ( typeof define === 'function' && define.amd ) {
2925
+ // AMD
2926
+ define( 'packery/js/rect',rectDefinition );
2927
+ } else {
2928
+ // browser global
2929
+ window.Packery = window.Packery || {};
2930
+ window.Packery.Rect = rectDefinition();
2931
+ }
2932
+
2933
+ })( window );
2934
+
2935
+ /**
2936
+ * Packer
2937
+ * bin-packing algorithm
2938
+ */
2939
+
2940
+ ( function( window ) {
2941
+
2942
+
2943
+
2944
+ // -------------------------- Packer -------------------------- //
2945
+
2946
+ function packerDefinition( Rect ) {
2947
+
2948
+ /**
2949
+ * @param {Number} width
2950
+ * @param {Number} height
2951
+ * @param {String} sortDirection
2952
+ * topLeft for vertical, leftTop for horizontal
2953
+ */
2954
+ function Packer( width, height, sortDirection ) {
2955
+ this.width = width || 0;
2956
+ this.height = height || 0;
2957
+ this.sortDirection = sortDirection || 'downwardLeftToRight';
2958
+
2959
+ this.reset();
2960
+ }
2961
+
2962
+ Packer.prototype.reset = function() {
2963
+ this.spaces = [];
2964
+ this.newSpaces = [];
2965
+
2966
+ var initialSpace = new Rect({
2967
+ x: 0,
2968
+ y: 0,
2969
+ width: this.width,
2970
+ height: this.height
2971
+ });
2972
+
2973
+ this.spaces.push( initialSpace );
2974
+ // set sorter
2975
+ this.sorter = sorters[ this.sortDirection ] || sorters.downwardLeftToRight;
2976
+ };
2977
+
2978
+ // change x and y of rect to fit with in Packer's available spaces
2979
+ Packer.prototype.pack = function( rect ) {
2980
+ for ( var i=0, len = this.spaces.length; i < len; i++ ) {
2981
+ var space = this.spaces[i];
2982
+ if ( space.canFit( rect ) ) {
2983
+ this.placeInSpace( rect, space );
2984
+ break;
2985
+ }
2986
+ }
2987
+ };
2988
+
2989
+ Packer.prototype.placeInSpace = function( rect, space ) {
2990
+ // place rect in space
2991
+ rect.x = space.x;
2992
+ rect.y = space.y;
2993
+
2994
+ this.placed( rect );
2995
+ };
2996
+
2997
+ // update spaces with placed rect
2998
+ Packer.prototype.placed = function( rect ) {
2999
+ // update spaces
3000
+ var revisedSpaces = [];
3001
+ for ( var i=0, len = this.spaces.length; i < len; i++ ) {
3002
+ var space = this.spaces[i];
3003
+ var newSpaces = space.getMaximalFreeRects( rect );
3004
+ // add either the original space or the new spaces to the revised spaces
3005
+ if ( newSpaces ) {
3006
+ revisedSpaces.push.apply( revisedSpaces, newSpaces );
3007
+ } else {
3008
+ revisedSpaces.push( space );
3009
+ }
3010
+ }
3011
+
3012
+ this.spaces = revisedSpaces;
3013
+
3014
+ // remove redundant spaces
3015
+ Packer.mergeRects( this.spaces );
3016
+
3017
+ this.spaces.sort( this.sorter );
3018
+ };
3019
+
3020
+ // -------------------------- utility functions -------------------------- //
3021
+
3022
+ /**
3023
+ * Remove redundant rectangle from array of rectangles
3024
+ * @param {Array} rects: an array of Rects
3025
+ * @returns {Array} rects: an array of Rects
3026
+ **/
3027
+ Packer.mergeRects = function( rects ) {
3028
+ for ( var i=0, len = rects.length; i < len; i++ ) {
3029
+ var rect = rects[i];
3030
+ // skip over this rect if it was already removed
3031
+ if ( !rect ) {
3032
+ continue;
3033
+ }
3034
+ // clone rects we're testing, remove this rect
3035
+ var compareRects = rects.slice(0);
3036
+ // do not compare with self
3037
+ compareRects.splice( i, 1 );
3038
+ // compare this rect with others
3039
+ var removedCount = 0;
3040
+ for ( var j=0, jLen = compareRects.length; j < jLen; j++ ) {
3041
+ var compareRect = compareRects[j];
3042
+ // if this rect contains another,
3043
+ // remove that rect from test collection
3044
+ var indexAdjust = i > j ? 0 : 1;
3045
+ if ( rect.contains( compareRect ) ) {
3046
+ // console.log( 'current test rects:' + testRects.length, testRects );
3047
+ // console.log( i, j, indexAdjust, rect, compareRect );
3048
+ rects.splice( j + indexAdjust - removedCount, 1 );
3049
+ removedCount++;
3050
+ }
3051
+ }
3052
+ }
3053
+
3054
+ return rects;
3055
+ };
3056
+
3057
+
3058
+ // -------------------------- sorters -------------------------- //
3059
+
3060
+ // functions for sorting rects in order
3061
+ var sorters = {
3062
+ // top down, then left to right
3063
+ downwardLeftToRight: function( a, b ) {
3064
+ return a.y - b.y || a.x - b.x;
3065
+ },
3066
+ // left to right, then top down
3067
+ rightwardTopToBottom: function( a, b ) {
3068
+ return a.x - b.x || a.y - b.y;
3069
+ }
3070
+ };
3071
+
3072
+
3073
+ // -------------------------- -------------------------- //
3074
+
3075
+ return Packer;
3076
+
3077
+ }
3078
+
3079
+ // -------------------------- transport -------------------------- //
3080
+
3081
+ if ( typeof define === 'function' && define.amd ) {
3082
+ // AMD
3083
+ define( 'packery/js/packer',[ './rect' ], packerDefinition );
3084
+ } else {
3085
+ // browser global
3086
+ var Packery = window.Packery = window.Packery || {};
3087
+ Packery.Packer = packerDefinition( Packery.Rect );
3088
+ }
3089
+
3090
+ })( window );
3091
+
3092
+ /**
3093
+ * Packery Item Element
3094
+ **/
3095
+
3096
+ ( function( window ) {
3097
+
3098
+
3099
+
3100
+ // -------------------------- Item -------------------------- //
3101
+
3102
+ function itemDefinition( getStyleProperty, Outlayer, Rect ) {
3103
+
3104
+ var transformProperty = getStyleProperty('transform');
3105
+
3106
+ // sub-class Item
3107
+ var Item = function PackeryItem() {
3108
+ Outlayer.Item.apply( this, arguments );
3109
+ };
3110
+
3111
+ Item.prototype = new Outlayer.Item();
3112
+
3113
+ var protoCreate = Item.prototype._create;
3114
+ Item.prototype._create = function() {
3115
+ // call default _create logic
3116
+ protoCreate.call( this );
3117
+ this.rect = new Rect();
3118
+ // rect used for placing, in drag or Packery.fit()
3119
+ this.placeRect = new Rect();
3120
+ };
3121
+
3122
+ // -------------------------- drag -------------------------- //
3123
+
3124
+ Item.prototype.dragStart = function() {
3125
+ this.getPosition();
3126
+ this.removeTransitionStyles();
3127
+ // remove transform property from transition
3128
+ if ( this.isTransitioning && transformProperty ) {
3129
+ this.element.style[ transformProperty ] = 'none';
3130
+ }
3131
+ this.getSize();
3132
+ // create place rect, used for position when dragged then dropped
3133
+ // or when positioning
3134
+ this.isPlacing = true;
3135
+ this.needsPositioning = false;
3136
+ this.positionPlaceRect( this.position.x, this.position.y );
3137
+ this.isTransitioning = false;
3138
+ this.didDrag = false;
3139
+ };
3140
+
3141
+ /**
3142
+ * handle item when it is dragged
3143
+ * @param {Number} x - horizontal position of dragged item
3144
+ * @param {Number} y - vertical position of dragged item
3145
+ */
3146
+ Item.prototype.dragMove = function( x, y ) {
3147
+ this.didDrag = true;
3148
+ var packerySize = this.layout.size;
3149
+ x -= packerySize.paddingLeft;
3150
+ y -= packerySize.paddingTop;
3151
+ this.positionPlaceRect( x, y );
3152
+ };
3153
+
3154
+ Item.prototype.dragStop = function() {
3155
+ this.getPosition();
3156
+ var isDiffX = this.position.x !== this.placeRect.x;
3157
+ var isDiffY = this.position.y !== this.placeRect.y;
3158
+ // set post-drag positioning flag
3159
+ this.needsPositioning = isDiffX || isDiffY;
3160
+ // reset flag
3161
+ this.didDrag = false;
3162
+ };
3163
+
3164
+ // -------------------------- placing -------------------------- //
3165
+
3166
+ /**
3167
+ * position a rect that will occupy space in the packer
3168
+ * @param {Number} x
3169
+ * @param {Number} y
3170
+ * @param {Boolean} isMaxYContained
3171
+ */
3172
+ Item.prototype.positionPlaceRect = function( x, y, isMaxYOpen ) {
3173
+ this.placeRect.x = this.getPlaceRectCoord( x, true );
3174
+ this.placeRect.y = this.getPlaceRectCoord( y, false, isMaxYOpen );
3175
+ };
3176
+
3177
+ /**
3178
+ * get x/y coordinate for place rect
3179
+ * @param {Number} coord - x or y
3180
+ * @param {Boolean} isX
3181
+ * @param {Boolean} isMaxOpen - does not limit value to outer bound
3182
+ * @returns {Number} coord - processed x or y
3183
+ */
3184
+ Item.prototype.getPlaceRectCoord = function( coord, isX, isMaxOpen ) {
3185
+ var measure = isX ? 'Width' : 'Height';
3186
+ var size = this.size[ 'outer' + measure ];
3187
+ var segment = this.layout[ isX ? 'columnWidth' : 'rowHeight' ];
3188
+ var parentSize = this.layout.size[ 'inner' + measure ];
3189
+
3190
+ // additional parentSize calculations for Y
3191
+ if ( !isX ) {
3192
+ parentSize = Math.max( parentSize, this.layout.maxY );
3193
+ // prevent gutter from bumping up height when non-vertical grid
3194
+ if ( !this.layout.rowHeight ) {
3195
+ parentSize -= this.layout.gutter;
3196
+ }
3197
+ }
3198
+
3199
+ var max;
3200
+
3201
+ if ( segment ) {
3202
+ segment += this.layout.gutter;
3203
+ // allow for last column to reach the edge
3204
+ parentSize += isX ? this.layout.gutter : 0;
3205
+ // snap to closest segment
3206
+ coord = Math.round( coord / segment );
3207
+ // contain to outer bound
3208
+ // contain non-growing bound, allow growing bound to grow
3209
+ var mathMethod;
3210
+ if ( this.layout.options.isHorizontal ) {
3211
+ mathMethod = !isX ? 'floor' : 'ceil';
3212
+ } else {
3213
+ mathMethod = isX ? 'floor' : 'ceil';
3214
+ }
3215
+ var maxSegments = Math[ mathMethod ]( parentSize / segment );
3216
+ maxSegments -= Math.ceil( size / segment );
3217
+ max = maxSegments;
3218
+ } else {
3219
+ max = parentSize - size;
3220
+ }
3221
+
3222
+ coord = isMaxOpen ? coord : Math.min( coord, max );
3223
+ coord *= segment || 1;
3224
+
3225
+ return Math.max( 0, coord );
3226
+ };
3227
+
3228
+ Item.prototype.copyPlaceRectPosition = function() {
3229
+ this.rect.x = this.placeRect.x;
3230
+ this.rect.y = this.placeRect.y;
3231
+ };
3232
+
3233
+ return Item;
3234
+
3235
+ }
3236
+
3237
+ // -------------------------- transport -------------------------- //
3238
+
3239
+ if ( typeof define === 'function' && define.amd ) {
3240
+ // AMD
3241
+ define( 'packery/js/item',[
3242
+ 'get-style-property/get-style-property',
3243
+ 'outlayer/outlayer',
3244
+ './rect'
3245
+ ],
3246
+ itemDefinition );
3247
+ } else {
3248
+ // browser global
3249
+ window.Packery.Item = itemDefinition(
3250
+ window.getStyleProperty,
3251
+ window.Outlayer,
3252
+ window.Packery.Rect
3253
+ );
3254
+ }
3255
+
3256
+ })( window );
3257
+
3258
+ /*!
3259
+ * Packery v1.2.4
3260
+ * bin-packing layout library
3261
+ * http://packery.metafizzy.co
3262
+ *
3263
+ * Commercial use requires one-time purchase of a commercial license
3264
+ * http://packery.metafizzy.co/license.html
3265
+ *
3266
+ * Non-commercial use is licensed under the GPL v3 License
3267
+ *
3268
+ * Copyright 2014 Metafizzy
3269
+ */
3270
+
3271
+ ( function( window ) {
3272
+
3273
+
3274
+
3275
+ // -------------------------- Packery -------------------------- //
3276
+
3277
+ // used for AMD definition and requires
3278
+ function packeryDefinition( classie, getSize, Outlayer, Rect, Packer, Item ) {
3279
+
3280
+ // create an Outlayer layout class
3281
+ var Packery = Outlayer.create('packery');
3282
+ Packery.Item = Item;
3283
+
3284
+ Packery.prototype._create = function() {
3285
+ // call super
3286
+ Outlayer.prototype._create.call( this );
3287
+
3288
+ // initial properties
3289
+ this.packer = new Packer();
3290
+
3291
+ // Left over from v1.0
3292
+ this.stamp( this.options.stamped );
3293
+
3294
+ // create drag handlers
3295
+ var _this = this;
3296
+ this.handleDraggabilly = {
3297
+ dragStart: function( draggie ) {
3298
+ _this.itemDragStart( draggie.element );
3299
+ },
3300
+ dragMove: function( draggie ) {
3301
+ _this.itemDragMove( draggie.element, draggie.position.x, draggie.position.y );
3302
+ },
3303
+ dragEnd: function( draggie ) {
3304
+ _this.itemDragEnd( draggie.element );
3305
+ }
3306
+ };
3307
+
3308
+ this.handleUIDraggable = {
3309
+ start: function handleUIDraggableStart( event ) {
3310
+ _this.itemDragStart( event.currentTarget );
3311
+ },
3312
+ drag: function handleUIDraggableDrag( event, ui ) {
3313
+ _this.itemDragMove( event.currentTarget, ui.position.left, ui.position.top );
3314
+ },
3315
+ stop: function handleUIDraggableStop( event ) {
3316
+ _this.itemDragEnd( event.currentTarget );
3317
+ }
3318
+ };
3319
+
3320
+ };
3321
+
3322
+
3323
+ // ----- init & layout ----- //
3324
+
3325
+ /**
3326
+ * logic before any new layout
3327
+ */
3328
+ Packery.prototype._resetLayout = function() {
3329
+ this.getSize();
3330
+
3331
+ this._getMeasurements();
3332
+
3333
+ // reset packer
3334
+ var packer = this.packer;
3335
+ // packer settings, if horizontal or vertical
3336
+ if ( this.options.isHorizontal ) {
3337
+ packer.width = Number.POSITIVE_INFINITY;
3338
+ packer.height = this.size.innerHeight + this.gutter;
3339
+ packer.sortDirection = 'rightwardTopToBottom';
3340
+ } else {
3341
+ packer.width = this.size.innerWidth + this.gutter;
3342
+ packer.height = Number.POSITIVE_INFINITY;
3343
+ packer.sortDirection = 'downwardLeftToRight';
3344
+ }
3345
+
3346
+ packer.reset();
3347
+
3348
+ // layout
3349
+ this.maxY = 0;
3350
+ this.maxX = 0;
3351
+ };
3352
+
3353
+ /**
3354
+ * update columnWidth, rowHeight, & gutter
3355
+ * @private
3356
+ */
3357
+ Packery.prototype._getMeasurements = function() {
3358
+ this._getMeasurement( 'columnWidth', 'width' );
3359
+ this._getMeasurement( 'rowHeight', 'height' );
3360
+ this._getMeasurement( 'gutter', 'width' );
3361
+ };
3362
+
3363
+ Packery.prototype._getItemLayoutPosition = function( item ) {
3364
+ this._packItem( item );
3365
+ return item.rect;
3366
+ };
3367
+
3368
+
3369
+ /**
3370
+ * layout item in packer
3371
+ * @param {Packery.Item} item
3372
+ */
3373
+ Packery.prototype._packItem = function( item ) {
3374
+ this._setRectSize( item.element, item.rect );
3375
+ // pack the rect in the packer
3376
+ this.packer.pack( item.rect );
3377
+ this._setMaxXY( item.rect );
3378
+ };
3379
+
3380
+ /**
3381
+ * set max X and Y value, for size of container
3382
+ * @param {Packery.Rect} rect
3383
+ * @private
3384
+ */
3385
+ Packery.prototype._setMaxXY = function( rect ) {
3386
+ this.maxX = Math.max( rect.x + rect.width, this.maxX );
3387
+ this.maxY = Math.max( rect.y + rect.height, this.maxY );
3388
+ };
3389
+
3390
+ /**
3391
+ * set the width and height of a rect, applying columnWidth and rowHeight
3392
+ * @param {Element} elem
3393
+ * @param {Packery.Rect} rect
3394
+ */
3395
+ Packery.prototype._setRectSize = function( elem, rect ) {
3396
+ var size = getSize( elem );
3397
+ var w = size.outerWidth;
3398
+ var h = size.outerHeight;
3399
+ // size for columnWidth and rowHeight, if available
3400
+ // only check if size is non-zero, #177
3401
+ if ( w || h ) {
3402
+ var colW = this.columnWidth + this.gutter;
3403
+ var rowH = this.rowHeight + this.gutter;
3404
+ w = this.columnWidth ? Math.ceil( w / colW ) * colW : w + this.gutter;
3405
+ h = this.rowHeight ? Math.ceil( h / rowH ) * rowH : h + this.gutter;
3406
+ }
3407
+ // rect must fit in packer
3408
+ rect.width = Math.min( w, this.packer.width );
3409
+ rect.height = Math.min( h, this.packer.height );
3410
+ };
3411
+
3412
+ Packery.prototype._getContainerSize = function() {
3413
+ if ( this.options.isHorizontal ) {
3414
+ return {
3415
+ width: this.maxX - this.gutter
3416
+ };
3417
+ } else {
3418
+ return {
3419
+ height: this.maxY - this.gutter
3420
+ };
3421
+ }
3422
+ };
3423
+
3424
+
3425
+ // -------------------------- stamp -------------------------- //
3426
+
3427
+ /**
3428
+ * makes space for element
3429
+ * @param {Element} elem
3430
+ */
3431
+ Packery.prototype._manageStamp = function( elem ) {
3432
+
3433
+ var item = this.getItem( elem );
3434
+ var rect;
3435
+ if ( item && item.isPlacing ) {
3436
+ rect = item.placeRect;
3437
+ } else {
3438
+ var offset = this._getElementOffset( elem );
3439
+ rect = new Rect({
3440
+ x: this.options.isOriginLeft ? offset.left : offset.right,
3441
+ y: this.options.isOriginTop ? offset.top : offset.bottom
3442
+ });
3443
+ }
3444
+
3445
+ this._setRectSize( elem, rect );
3446
+ // save its space in the packer
3447
+ this.packer.placed( rect );
3448
+ this._setMaxXY( rect );
3449
+ };
3450
+
3451
+ // -------------------------- methods -------------------------- //
3452
+
3453
+ function verticalSorter( a, b ) {
3454
+ return a.position.y - b.position.y || a.position.x - b.position.x;
3455
+ }
3456
+
3457
+ function horizontalSorter( a, b ) {
3458
+ return a.position.x - b.position.x || a.position.y - b.position.y;
3459
+ }
3460
+
3461
+ Packery.prototype.sortItemsByPosition = function() {
3462
+ var sorter = this.options.isHorizontal ? horizontalSorter : verticalSorter;
3463
+ this.items.sort( sorter );
3464
+ };
3465
+
3466
+ /**
3467
+ * Fit item element in its current position
3468
+ * Packery will position elements around it
3469
+ * useful for expanding elements
3470
+ *
3471
+ * @param {Element} elem
3472
+ * @param {Number} x - horizontal destination position, optional
3473
+ * @param {Number} y - vertical destination position, optional
3474
+ */
3475
+ Packery.prototype.fit = function( elem, x, y ) {
3476
+ var item = this.getItem( elem );
3477
+ if ( !item ) {
3478
+ return;
3479
+ }
3480
+
3481
+ // prepare internal properties
3482
+ this._getMeasurements();
3483
+
3484
+ // stamp item to get it out of layout
3485
+ this.stamp( item.element );
3486
+ // required for positionPlaceRect
3487
+ item.getSize();
3488
+ // set placing flag
3489
+ item.isPlacing = true;
3490
+ // fall back to current position for fitting
3491
+ x = x === undefined ? item.rect.x: x;
3492
+ y = y === undefined ? item.rect.y: y;
3493
+
3494
+ // position it best at its destination
3495
+ item.positionPlaceRect( x, y, true );
3496
+
3497
+ this._bindFitEvents( item );
3498
+ item.moveTo( item.placeRect.x, item.placeRect.y );
3499
+ // layout everything else
3500
+ this.layout();
3501
+
3502
+ // return back to regularly scheduled programming
3503
+ this.unstamp( item.element );
3504
+ this.sortItemsByPosition();
3505
+ // un set placing flag, back to normal
3506
+ item.isPlacing = false;
3507
+ // copy place rect position
3508
+ item.copyPlaceRectPosition();
3509
+ };
3510
+
3511
+ /**
3512
+ * emit event when item is fit and other items are laid out
3513
+ * @param {Packery.Item} item
3514
+ * @private
3515
+ */
3516
+ Packery.prototype._bindFitEvents = function( item ) {
3517
+ var _this = this;
3518
+ var ticks = 0;
3519
+ function tick() {
3520
+ ticks++;
3521
+ if ( ticks !== 2 ) {
3522
+ return;
3523
+ }
3524
+ _this.emitEvent( 'fitComplete', [ _this, item ] );
3525
+ }
3526
+ // when item is laid out
3527
+ item.on( 'layout', function() {
3528
+ tick();
3529
+ return true;
3530
+ });
3531
+ // when all items are laid out
3532
+ this.on( 'layoutComplete', function() {
3533
+ tick();
3534
+ return true;
3535
+ });
3536
+ };
3537
+
3538
+ // -------------------------- resize -------------------------- //
3539
+
3540
+ // debounced, layout on resize
3541
+ Packery.prototype.resize = function() {
3542
+ // don't trigger if size did not change
3543
+ var size = getSize( this.element );
3544
+ // check that this.size and size are there
3545
+ // IE8 triggers resize on body size change, so they might not be
3546
+ var hasSizes = this.size && size;
3547
+ var innerSize = this.options.isHorizontal ? 'innerHeight' : 'innerWidth';
3548
+ if ( hasSizes && size[ innerSize ] === this.size[ innerSize ] ) {
3549
+ return;
3550
+ }
3551
+
3552
+ this.layout();
3553
+ };
3554
+
3555
+ // -------------------------- drag -------------------------- //
3556
+
3557
+ /**
3558
+ * handle an item drag start event
3559
+ * @param {Element} elem
3560
+ */
3561
+ Packery.prototype.itemDragStart = function( elem ) {
3562
+ this.stamp( elem );
3563
+ var item = this.getItem( elem );
3564
+ if ( item ) {
3565
+ item.dragStart();
3566
+ }
3567
+ };
3568
+
3569
+ /**
3570
+ * handle an item drag move event
3571
+ * @param {Element} elem
3572
+ * @param {Number} x - horizontal change in position
3573
+ * @param {Number} y - vertical change in position
3574
+ */
3575
+ Packery.prototype.itemDragMove = function( elem, x, y ) {
3576
+ var item = this.getItem( elem );
3577
+ if ( item ) {
3578
+ item.dragMove( x, y );
3579
+ }
3580
+
3581
+ // debounce
3582
+ var _this = this;
3583
+ // debounce triggering layout
3584
+ function delayed() {
3585
+ _this.layout();
3586
+ delete _this.dragTimeout;
3587
+ }
3588
+
3589
+ this.clearDragTimeout();
3590
+
3591
+ this.dragTimeout = setTimeout( delayed, 40 );
3592
+ };
3593
+
3594
+ Packery.prototype.clearDragTimeout = function() {
3595
+ if ( this.dragTimeout ) {
3596
+ clearTimeout( this.dragTimeout );
3597
+ }
3598
+ };
3599
+
3600
+ /**
3601
+ * handle an item drag end event
3602
+ * @param {Element} elem
3603
+ */
3604
+ Packery.prototype.itemDragEnd = function( elem ) {
3605
+ var item = this.getItem( elem );
3606
+ var itemDidDrag;
3607
+ if ( item ) {
3608
+ itemDidDrag = item.didDrag;
3609
+ item.dragStop();
3610
+ }
3611
+ // if elem didn't move, or if it doesn't need positioning
3612
+ // unignore and unstamp and call it a day
3613
+ if ( !item || ( !itemDidDrag && !item.needsPositioning ) ) {
3614
+ this.unstamp( elem );
3615
+ return;
3616
+ }
3617
+ // procced with dragged item
3618
+
3619
+ classie.add( item.element, 'is-positioning-post-drag' );
3620
+
3621
+ // save this var, as it could get reset in dragStart
3622
+ var onLayoutComplete = this._getDragEndLayoutComplete( elem, item );
3623
+
3624
+ if ( item.needsPositioning ) {
3625
+ item.on( 'layout', onLayoutComplete );
3626
+ item.moveTo( item.placeRect.x, item.placeRect.y );
3627
+ } else if ( item ) {
3628
+ // item didn't need placement
3629
+ item.copyPlaceRectPosition();
3630
+ }
3631
+
3632
+ this.clearDragTimeout();
3633
+ this.on( 'layoutComplete', onLayoutComplete );
3634
+ this.layout();
3635
+
3636
+ };
3637
+
3638
+ /**
3639
+ * get drag end callback
3640
+ * @param {Element} elem
3641
+ * @param {Packery.Item} item
3642
+ * @returns {Function} onLayoutComplete
3643
+ */
3644
+ Packery.prototype._getDragEndLayoutComplete = function( elem, item ) {
3645
+ var itemNeedsPositioning = item && item.needsPositioning;
3646
+ var completeCount = 0;
3647
+ var asyncCount = itemNeedsPositioning ? 2 : 1;
3648
+ var _this = this;
3649
+
3650
+ return function onLayoutComplete() {
3651
+ completeCount++;
3652
+ // don't proceed if not complete
3653
+ if ( completeCount !== asyncCount ) {
3654
+ return true;
3655
+ }
3656
+ // reset item
3657
+ if ( item ) {
3658
+ classie.remove( item.element, 'is-positioning-post-drag' );
3659
+ item.isPlacing = false;
3660
+ item.copyPlaceRectPosition();
3661
+ }
3662
+
3663
+ _this.unstamp( elem );
3664
+ // only sort when item moved
3665
+ _this.sortItemsByPosition();
3666
+
3667
+ // emit item drag event now that everything is done
3668
+ if ( itemNeedsPositioning ) {
3669
+ _this.emitEvent( 'dragItemPositioned', [ _this, item ] );
3670
+ }
3671
+ // listen once
3672
+ return true;
3673
+ };
3674
+ };
3675
+
3676
+ /**
3677
+ * binds Draggabilly events
3678
+ * @param {Draggabilly} draggie
3679
+ */
3680
+ Packery.prototype.bindDraggabillyEvents = function( draggie ) {
3681
+ draggie.on( 'dragStart', this.handleDraggabilly.dragStart );
3682
+ draggie.on( 'dragMove', this.handleDraggabilly.dragMove );
3683
+ draggie.on( 'dragEnd', this.handleDraggabilly.dragEnd );
3684
+ };
3685
+
3686
+ /**
3687
+ * binds jQuery UI Draggable events
3688
+ * @param {jQuery} $elems
3689
+ */
3690
+ Packery.prototype.bindUIDraggableEvents = function( $elems ) {
3691
+ $elems
3692
+ .on( 'dragstart', this.handleUIDraggable.start )
3693
+ .on( 'drag', this.handleUIDraggable.drag )
3694
+ .on( 'dragstop', this.handleUIDraggable.stop );
3695
+ };
3696
+
3697
+ Packery.Rect = Rect;
3698
+ Packery.Packer = Packer;
3699
+
3700
+ return Packery;
3701
+
3702
+ }
3703
+
3704
+ // -------------------------- transport -------------------------- //
3705
+
3706
+ if ( typeof define === 'function' && define.amd ) {
3707
+ // AMD
3708
+ define( [
3709
+ 'classie/classie',
3710
+ 'get-size/get-size',
3711
+ 'outlayer/outlayer',
3712
+ 'packery/js/rect',
3713
+ 'packery/js/packer',
3714
+ 'packery/js/item'
3715
+ ],
3716
+ packeryDefinition );
3717
+ } else {
3718
+ // browser global
3719
+ window.Packery = packeryDefinition(
3720
+ window.classie,
3721
+ window.getSize,
3722
+ window.Outlayer,
3723
+ window.Packery.Rect,
3724
+ window.Packery.Packer,
3725
+ window.Packery.Item
3726
+ );
3727
+ }
3728
+
3729
+ })( window );