jekyll-theme-glueckkanja 1.2.5 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 63763fd056908d87b773e22dacdb5b3ad4dce9ce7bb312ebd233b8d2b6921e32
4
- data.tar.gz: be2f9a967effa6324a789500902a7b4435fb5554753891d5e3c6369ea830d17f
3
+ metadata.gz: 3b989613228f43bd36ae3489391fcd0b169678c40f72276c7cb8fa4a872e678e
4
+ data.tar.gz: ea13dc1b121607d7da915f705863481d2995118089ffa7183eb483959cbd552f
5
5
  SHA512:
6
- metadata.gz: ea2c6c6ed9d3f5545bfb705372afe49607a26be8496e391490673b12853f1fd69399cbd7890b5abfab79bebe9233fa10bdf950573293ce2ee1fe4ea6ea2265f5
7
- data.tar.gz: 91e90dd4fed23ab58aaa49558f8f44e17c352569b25660c9db50482d742c0f28963ca8946b8612b268fad89939d0f052de03aa6b7b106cbd1a0a454d3bc6ba53
6
+ metadata.gz: ceda45ba430bf101f72634dab00b0e030188783ef23d0da40586089485528106239e0dfa23d927be9fd889fda9bad5477a4d696946f5eda45fb5aea028829d2a
7
+ data.tar.gz: ad0a484e5560f391a33126febefe1445c711a78db0e67c67949930d278a90a2b70e4904cb46089fb740fa19093108899b9edccd75746fba4ce8b3ef039fe36ae
@@ -20,6 +20,7 @@
20
20
  <!-- Unify JavaScript -->
21
21
  <script type="text/javascript" charset="UTF-8" src="{{site.baseurl}}/assets/js/hs.core.js"></script>
22
22
  <script type="text/javascript" charset="UTF-8" src="{{site.baseurl}}/assets/js/components/hs.cubeportfolio.js"></script>
23
+ <script type="text/javascript" charset="UTF-8" src="{{site.baseurl}}/assets/js/vendor/masonry.pkgd.js"></script>
23
24
  <script type="text/javascript" charset="UTF-8" src="{{site.baseurl}}/assets/js/vendor/jquery.cubeportfolio.min.js"></script>
24
25
  <script type="text/javascript" charset="UTF-8" src="{{site.baseurl}}/assets/js/vendor/jquery.fancybox.min.js"></script>
25
26
  <script type="text/javascript" charset="UTF-8" src="{{site.baseurl}}/assets/js/hs.popup.js"></script>
@@ -139,4 +140,4 @@ var google_remarketing_only = false;
139
140
  "url": "{{site.url}}"
140
141
  }
141
142
  </script>
142
- <!-- Scripts END -->
143
+ <!-- Scripts END -->
@@ -0,0 +1,2503 @@
1
+ /*!
2
+ * Masonry PACKAGED v4.2.2
3
+ * Cascading grid layout library
4
+ * https://masonry.desandro.com
5
+ * MIT License
6
+ * by David DeSandro
7
+ */
8
+
9
+ /**
10
+ * Bridget makes jQuery widgets
11
+ * v2.0.1
12
+ * MIT license
13
+ */
14
+
15
+ /* jshint browser: true, strict: true, undef: true, unused: true */
16
+
17
+ ( function( window, factory ) {
18
+ // universal module definition
19
+ /*jshint strict: false */ /* globals define, module, require */
20
+ if ( typeof define == 'function' && define.amd ) {
21
+ // AMD
22
+ define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
23
+ return factory( window, jQuery );
24
+ });
25
+ } else if ( typeof module == 'object' && module.exports ) {
26
+ // CommonJS
27
+ module.exports = factory(
28
+ window,
29
+ require('jquery')
30
+ );
31
+ } else {
32
+ // browser global
33
+ window.jQueryBridget = factory(
34
+ window,
35
+ window.jQuery
36
+ );
37
+ }
38
+
39
+ }( window, function factory( window, jQuery ) {
40
+ 'use strict';
41
+
42
+ // ----- utils ----- //
43
+
44
+ var arraySlice = Array.prototype.slice;
45
+
46
+ // helper function for logging errors
47
+ // $.error breaks jQuery chaining
48
+ var console = window.console;
49
+ var logError = typeof console == 'undefined' ? function() {} :
50
+ function( message ) {
51
+ console.error( message );
52
+ };
53
+
54
+ // ----- jQueryBridget ----- //
55
+
56
+ function jQueryBridget( namespace, PluginClass, $ ) {
57
+ $ = $ || jQuery || window.jQuery;
58
+ if ( !$ ) {
59
+ return;
60
+ }
61
+
62
+ // add option method -> $().plugin('option', {...})
63
+ if ( !PluginClass.prototype.option ) {
64
+ // option setter
65
+ PluginClass.prototype.option = function( opts ) {
66
+ // bail out if not an object
67
+ if ( !$.isPlainObject( opts ) ){
68
+ return;
69
+ }
70
+ this.options = $.extend( true, this.options, opts );
71
+ };
72
+ }
73
+
74
+ // make jQuery plugin
75
+ $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
76
+ if ( typeof arg0 == 'string' ) {
77
+ // method call $().plugin( 'methodName', { options } )
78
+ // shift arguments by 1
79
+ var args = arraySlice.call( arguments, 1 );
80
+ return methodCall( this, arg0, args );
81
+ }
82
+ // just $().plugin({ options })
83
+ plainCall( this, arg0 );
84
+ return this;
85
+ };
86
+
87
+ // $().plugin('methodName')
88
+ function methodCall( $elems, methodName, args ) {
89
+ var returnValue;
90
+ var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
91
+
92
+ $elems.each( function( i, elem ) {
93
+ // get instance
94
+ var instance = $.data( elem, namespace );
95
+ if ( !instance ) {
96
+ logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
97
+ pluginMethodStr );
98
+ return;
99
+ }
100
+
101
+ var method = instance[ methodName ];
102
+ if ( !method || methodName.charAt(0) == '_' ) {
103
+ logError( pluginMethodStr + ' is not a valid method' );
104
+ return;
105
+ }
106
+
107
+ // apply method, get return value
108
+ var value = method.apply( instance, args );
109
+ // set return value if value is returned, use only first value
110
+ returnValue = returnValue === undefined ? value : returnValue;
111
+ });
112
+
113
+ return returnValue !== undefined ? returnValue : $elems;
114
+ }
115
+
116
+ function plainCall( $elems, options ) {
117
+ $elems.each( function( i, elem ) {
118
+ var instance = $.data( elem, namespace );
119
+ if ( instance ) {
120
+ // set options & init
121
+ instance.option( options );
122
+ instance._init();
123
+ } else {
124
+ // initialize new instance
125
+ instance = new PluginClass( elem, options );
126
+ $.data( elem, namespace, instance );
127
+ }
128
+ });
129
+ }
130
+
131
+ updateJQuery( $ );
132
+
133
+ }
134
+
135
+ // ----- updateJQuery ----- //
136
+
137
+ // set $.bridget for v1 backwards compatibility
138
+ function updateJQuery( $ ) {
139
+ if ( !$ || ( $ && $.bridget ) ) {
140
+ return;
141
+ }
142
+ $.bridget = jQueryBridget;
143
+ }
144
+
145
+ updateJQuery( jQuery || window.jQuery );
146
+
147
+ // ----- ----- //
148
+
149
+ return jQueryBridget;
150
+
151
+ }));
152
+
153
+ /**
154
+ * EvEmitter v1.1.0
155
+ * Lil' event emitter
156
+ * MIT License
157
+ */
158
+
159
+ /* jshint unused: true, undef: true, strict: true */
160
+
161
+ ( function( global, factory ) {
162
+ // universal module definition
163
+ /* jshint strict: false */ /* globals define, module, window */
164
+ if ( typeof define == 'function' && define.amd ) {
165
+ // AMD - RequireJS
166
+ define( 'ev-emitter/ev-emitter',factory );
167
+ } else if ( typeof module == 'object' && module.exports ) {
168
+ // CommonJS - Browserify, Webpack
169
+ module.exports = factory();
170
+ } else {
171
+ // Browser globals
172
+ global.EvEmitter = factory();
173
+ }
174
+
175
+ }( typeof window != 'undefined' ? window : this, function() {
176
+
177
+
178
+
179
+ function EvEmitter() {}
180
+
181
+ var proto = EvEmitter.prototype;
182
+
183
+ proto.on = function( eventName, listener ) {
184
+ if ( !eventName || !listener ) {
185
+ return;
186
+ }
187
+ // set events hash
188
+ var events = this._events = this._events || {};
189
+ // set listeners array
190
+ var listeners = events[ eventName ] = events[ eventName ] || [];
191
+ // only add once
192
+ if ( listeners.indexOf( listener ) == -1 ) {
193
+ listeners.push( listener );
194
+ }
195
+
196
+ return this;
197
+ };
198
+
199
+ proto.once = function( eventName, listener ) {
200
+ if ( !eventName || !listener ) {
201
+ return;
202
+ }
203
+ // add event
204
+ this.on( eventName, listener );
205
+ // set once flag
206
+ // set onceEvents hash
207
+ var onceEvents = this._onceEvents = this._onceEvents || {};
208
+ // set onceListeners object
209
+ var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
210
+ // set flag
211
+ onceListeners[ listener ] = true;
212
+
213
+ return this;
214
+ };
215
+
216
+ proto.off = function( eventName, listener ) {
217
+ var listeners = this._events && this._events[ eventName ];
218
+ if ( !listeners || !listeners.length ) {
219
+ return;
220
+ }
221
+ var index = listeners.indexOf( listener );
222
+ if ( index != -1 ) {
223
+ listeners.splice( index, 1 );
224
+ }
225
+
226
+ return this;
227
+ };
228
+
229
+ proto.emitEvent = function( eventName, args ) {
230
+ var listeners = this._events && this._events[ eventName ];
231
+ if ( !listeners || !listeners.length ) {
232
+ return;
233
+ }
234
+ // copy over to avoid interference if .off() in listener
235
+ listeners = listeners.slice(0);
236
+ args = args || [];
237
+ // once stuff
238
+ var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
239
+
240
+ for ( var i=0; i < listeners.length; i++ ) {
241
+ var listener = listeners[i]
242
+ var isOnce = onceListeners && onceListeners[ listener ];
243
+ if ( isOnce ) {
244
+ // remove listener
245
+ // remove before trigger to prevent recursion
246
+ this.off( eventName, listener );
247
+ // unset once flag
248
+ delete onceListeners[ listener ];
249
+ }
250
+ // trigger listener
251
+ listener.apply( this, args );
252
+ }
253
+
254
+ return this;
255
+ };
256
+
257
+ proto.allOff = function() {
258
+ delete this._events;
259
+ delete this._onceEvents;
260
+ };
261
+
262
+ return EvEmitter;
263
+
264
+ }));
265
+
266
+ /*!
267
+ * getSize v2.0.3
268
+ * measure size of elements
269
+ * MIT license
270
+ */
271
+
272
+ /* jshint browser: true, strict: true, undef: true, unused: true */
273
+ /* globals console: false */
274
+
275
+ ( function( window, factory ) {
276
+ /* jshint strict: false */ /* globals define, module */
277
+ if ( typeof define == 'function' && define.amd ) {
278
+ // AMD
279
+ define( 'get-size/get-size',factory );
280
+ } else if ( typeof module == 'object' && module.exports ) {
281
+ // CommonJS
282
+ module.exports = factory();
283
+ } else {
284
+ // browser global
285
+ window.getSize = factory();
286
+ }
287
+
288
+ })( window, function factory() {
289
+ 'use strict';
290
+
291
+ // -------------------------- helpers -------------------------- //
292
+
293
+ // get a number from a string, not a percentage
294
+ function getStyleSize( value ) {
295
+ var num = parseFloat( value );
296
+ // not a percent like '100%', and a number
297
+ var isValid = value.indexOf('%') == -1 && !isNaN( num );
298
+ return isValid && num;
299
+ }
300
+
301
+ function noop() {}
302
+
303
+ var logError = typeof console == 'undefined' ? noop :
304
+ function( message ) {
305
+ console.error( message );
306
+ };
307
+
308
+ // -------------------------- measurements -------------------------- //
309
+
310
+ var measurements = [
311
+ 'paddingLeft',
312
+ 'paddingRight',
313
+ 'paddingTop',
314
+ 'paddingBottom',
315
+ 'marginLeft',
316
+ 'marginRight',
317
+ 'marginTop',
318
+ 'marginBottom',
319
+ 'borderLeftWidth',
320
+ 'borderRightWidth',
321
+ 'borderTopWidth',
322
+ 'borderBottomWidth'
323
+ ];
324
+
325
+ var measurementsLength = measurements.length;
326
+
327
+ function getZeroSize() {
328
+ var size = {
329
+ width: 0,
330
+ height: 0,
331
+ innerWidth: 0,
332
+ innerHeight: 0,
333
+ outerWidth: 0,
334
+ outerHeight: 0
335
+ };
336
+ for ( var i=0; i < measurementsLength; i++ ) {
337
+ var measurement = measurements[i];
338
+ size[ measurement ] = 0;
339
+ }
340
+ return size;
341
+ }
342
+
343
+ // -------------------------- getStyle -------------------------- //
344
+
345
+ /**
346
+ * getStyle, get style of element, check for Firefox bug
347
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=548397
348
+ */
349
+ function getStyle( elem ) {
350
+ var style = getComputedStyle( elem );
351
+ if ( !style ) {
352
+ logError( 'Style returned ' + style +
353
+ '. Are you running this code in a hidden iframe on Firefox? ' +
354
+ 'See https://bit.ly/getsizebug1' );
355
+ }
356
+ return style;
357
+ }
358
+
359
+ // -------------------------- setup -------------------------- //
360
+
361
+ var isSetup = false;
362
+
363
+ var isBoxSizeOuter;
364
+
365
+ /**
366
+ * setup
367
+ * check isBoxSizerOuter
368
+ * do on first getSize() rather than on page load for Firefox bug
369
+ */
370
+ function setup() {
371
+ // setup once
372
+ if ( isSetup ) {
373
+ return;
374
+ }
375
+ isSetup = true;
376
+
377
+ // -------------------------- box sizing -------------------------- //
378
+
379
+ /**
380
+ * Chrome & Safari measure the outer-width on style.width on border-box elems
381
+ * IE11 & Firefox<29 measures the inner-width
382
+ */
383
+ var div = document.createElement('div');
384
+ div.style.width = '200px';
385
+ div.style.padding = '1px 2px 3px 4px';
386
+ div.style.borderStyle = 'solid';
387
+ div.style.borderWidth = '1px 2px 3px 4px';
388
+ div.style.boxSizing = 'border-box';
389
+
390
+ var body = document.body || document.documentElement;
391
+ body.appendChild( div );
392
+ var style = getStyle( div );
393
+ // round value for browser zoom. desandro/masonry#928
394
+ isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;
395
+ getSize.isBoxSizeOuter = isBoxSizeOuter;
396
+
397
+ body.removeChild( div );
398
+ }
399
+
400
+ // -------------------------- getSize -------------------------- //
401
+
402
+ function getSize( elem ) {
403
+ setup();
404
+
405
+ // use querySeletor if elem is string
406
+ if ( typeof elem == 'string' ) {
407
+ elem = document.querySelector( elem );
408
+ }
409
+
410
+ // do not proceed on non-objects
411
+ if ( !elem || typeof elem != 'object' || !elem.nodeType ) {
412
+ return;
413
+ }
414
+
415
+ var style = getStyle( elem );
416
+
417
+ // if hidden, everything is 0
418
+ if ( style.display == 'none' ) {
419
+ return getZeroSize();
420
+ }
421
+
422
+ var size = {};
423
+ size.width = elem.offsetWidth;
424
+ size.height = elem.offsetHeight;
425
+
426
+ var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';
427
+
428
+ // get all measurements
429
+ for ( var i=0; i < measurementsLength; i++ ) {
430
+ var measurement = measurements[i];
431
+ var value = style[ measurement ];
432
+ var num = parseFloat( value );
433
+ // any 'auto', 'medium' value will be 0
434
+ size[ measurement ] = !isNaN( num ) ? num : 0;
435
+ }
436
+
437
+ var paddingWidth = size.paddingLeft + size.paddingRight;
438
+ var paddingHeight = size.paddingTop + size.paddingBottom;
439
+ var marginWidth = size.marginLeft + size.marginRight;
440
+ var marginHeight = size.marginTop + size.marginBottom;
441
+ var borderWidth = size.borderLeftWidth + size.borderRightWidth;
442
+ var borderHeight = size.borderTopWidth + size.borderBottomWidth;
443
+
444
+ var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;
445
+
446
+ // overwrite width and height if we can get it from style
447
+ var styleWidth = getStyleSize( style.width );
448
+ if ( styleWidth !== false ) {
449
+ size.width = styleWidth +
450
+ // add padding and border unless it's already including it
451
+ ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );
452
+ }
453
+
454
+ var styleHeight = getStyleSize( style.height );
455
+ if ( styleHeight !== false ) {
456
+ size.height = styleHeight +
457
+ // add padding and border unless it's already including it
458
+ ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );
459
+ }
460
+
461
+ size.innerWidth = size.width - ( paddingWidth + borderWidth );
462
+ size.innerHeight = size.height - ( paddingHeight + borderHeight );
463
+
464
+ size.outerWidth = size.width + marginWidth;
465
+ size.outerHeight = size.height + marginHeight;
466
+
467
+ return size;
468
+ }
469
+
470
+ return getSize;
471
+
472
+ });
473
+
474
+ /**
475
+ * matchesSelector v2.0.2
476
+ * matchesSelector( element, '.selector' )
477
+ * MIT license
478
+ */
479
+
480
+ /*jshint browser: true, strict: true, undef: true, unused: true */
481
+
482
+ ( function( window, factory ) {
483
+ /*global define: false, module: false */
484
+ 'use strict';
485
+ // universal module definition
486
+ if ( typeof define == 'function' && define.amd ) {
487
+ // AMD
488
+ define( 'desandro-matches-selector/matches-selector',factory );
489
+ } else if ( typeof module == 'object' && module.exports ) {
490
+ // CommonJS
491
+ module.exports = factory();
492
+ } else {
493
+ // browser global
494
+ window.matchesSelector = factory();
495
+ }
496
+
497
+ }( window, function factory() {
498
+ 'use strict';
499
+
500
+ var matchesMethod = ( function() {
501
+ var ElemProto = window.Element.prototype;
502
+ // check for the standard method name first
503
+ if ( ElemProto.matches ) {
504
+ return 'matches';
505
+ }
506
+ // check un-prefixed
507
+ if ( ElemProto.matchesSelector ) {
508
+ return 'matchesSelector';
509
+ }
510
+ // check vendor prefixes
511
+ var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
512
+
513
+ for ( var i=0; i < prefixes.length; i++ ) {
514
+ var prefix = prefixes[i];
515
+ var method = prefix + 'MatchesSelector';
516
+ if ( ElemProto[ method ] ) {
517
+ return method;
518
+ }
519
+ }
520
+ })();
521
+
522
+ return function matchesSelector( elem, selector ) {
523
+ return elem[ matchesMethod ]( selector );
524
+ };
525
+
526
+ }));
527
+
528
+ /**
529
+ * Fizzy UI utils v2.0.7
530
+ * MIT license
531
+ */
532
+
533
+ /*jshint browser: true, undef: true, unused: true, strict: true */
534
+
535
+ ( function( window, factory ) {
536
+ // universal module definition
537
+ /*jshint strict: false */ /*globals define, module, require */
538
+
539
+ if ( typeof define == 'function' && define.amd ) {
540
+ // AMD
541
+ define( 'fizzy-ui-utils/utils',[
542
+ 'desandro-matches-selector/matches-selector'
543
+ ], function( matchesSelector ) {
544
+ return factory( window, matchesSelector );
545
+ });
546
+ } else if ( typeof module == 'object' && module.exports ) {
547
+ // CommonJS
548
+ module.exports = factory(
549
+ window,
550
+ require('desandro-matches-selector')
551
+ );
552
+ } else {
553
+ // browser global
554
+ window.fizzyUIUtils = factory(
555
+ window,
556
+ window.matchesSelector
557
+ );
558
+ }
559
+
560
+ }( window, function factory( window, matchesSelector ) {
561
+
562
+
563
+
564
+ var utils = {};
565
+
566
+ // ----- extend ----- //
567
+
568
+ // extends objects
569
+ utils.extend = function( a, b ) {
570
+ for ( var prop in b ) {
571
+ a[ prop ] = b[ prop ];
572
+ }
573
+ return a;
574
+ };
575
+
576
+ // ----- modulo ----- //
577
+
578
+ utils.modulo = function( num, div ) {
579
+ return ( ( num % div ) + div ) % div;
580
+ };
581
+
582
+ // ----- makeArray ----- //
583
+
584
+ var arraySlice = Array.prototype.slice;
585
+
586
+ // turn element or nodeList into an array
587
+ utils.makeArray = function( obj ) {
588
+ if ( Array.isArray( obj ) ) {
589
+ // use object if already an array
590
+ return obj;
591
+ }
592
+ // return empty array if undefined or null. #6
593
+ if ( obj === null || obj === undefined ) {
594
+ return [];
595
+ }
596
+
597
+ var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
598
+ if ( isArrayLike ) {
599
+ // convert nodeList to array
600
+ return arraySlice.call( obj );
601
+ }
602
+
603
+ // array of single index
604
+ return [ obj ];
605
+ };
606
+
607
+ // ----- removeFrom ----- //
608
+
609
+ utils.removeFrom = function( ary, obj ) {
610
+ var index = ary.indexOf( obj );
611
+ if ( index != -1 ) {
612
+ ary.splice( index, 1 );
613
+ }
614
+ };
615
+
616
+ // ----- getParent ----- //
617
+
618
+ utils.getParent = function( elem, selector ) {
619
+ while ( elem.parentNode && elem != document.body ) {
620
+ elem = elem.parentNode;
621
+ if ( matchesSelector( elem, selector ) ) {
622
+ return elem;
623
+ }
624
+ }
625
+ };
626
+
627
+ // ----- getQueryElement ----- //
628
+
629
+ // use element as selector string
630
+ utils.getQueryElement = function( elem ) {
631
+ if ( typeof elem == 'string' ) {
632
+ return document.querySelector( elem );
633
+ }
634
+ return elem;
635
+ };
636
+
637
+ // ----- handleEvent ----- //
638
+
639
+ // enable .ontype to trigger from .addEventListener( elem, 'type' )
640
+ utils.handleEvent = function( event ) {
641
+ var method = 'on' + event.type;
642
+ if ( this[ method ] ) {
643
+ this[ method ]( event );
644
+ }
645
+ };
646
+
647
+ // ----- filterFindElements ----- //
648
+
649
+ utils.filterFindElements = function( elems, selector ) {
650
+ // make array of elems
651
+ elems = utils.makeArray( elems );
652
+ var ffElems = [];
653
+
654
+ elems.forEach( function( elem ) {
655
+ // check that elem is an actual element
656
+ if ( !( elem instanceof HTMLElement ) ) {
657
+ return;
658
+ }
659
+ // add elem if no selector
660
+ if ( !selector ) {
661
+ ffElems.push( elem );
662
+ return;
663
+ }
664
+ // filter & find items if we have a selector
665
+ // filter
666
+ if ( matchesSelector( elem, selector ) ) {
667
+ ffElems.push( elem );
668
+ }
669
+ // find children
670
+ var childElems = elem.querySelectorAll( selector );
671
+ // concat childElems to filterFound array
672
+ for ( var i=0; i < childElems.length; i++ ) {
673
+ ffElems.push( childElems[i] );
674
+ }
675
+ });
676
+
677
+ return ffElems;
678
+ };
679
+
680
+ // ----- debounceMethod ----- //
681
+
682
+ utils.debounceMethod = function( _class, methodName, threshold ) {
683
+ threshold = threshold || 100;
684
+ // original method
685
+ var method = _class.prototype[ methodName ];
686
+ var timeoutName = methodName + 'Timeout';
687
+
688
+ _class.prototype[ methodName ] = function() {
689
+ var timeout = this[ timeoutName ];
690
+ clearTimeout( timeout );
691
+
692
+ var args = arguments;
693
+ var _this = this;
694
+ this[ timeoutName ] = setTimeout( function() {
695
+ method.apply( _this, args );
696
+ delete _this[ timeoutName ];
697
+ }, threshold );
698
+ };
699
+ };
700
+
701
+ // ----- docReady ----- //
702
+
703
+ utils.docReady = function( callback ) {
704
+ var readyState = document.readyState;
705
+ if ( readyState == 'complete' || readyState == 'interactive' ) {
706
+ // do async to allow for other scripts to run. metafizzy/flickity#441
707
+ setTimeout( callback );
708
+ } else {
709
+ document.addEventListener( 'DOMContentLoaded', callback );
710
+ }
711
+ };
712
+
713
+ // ----- htmlInit ----- //
714
+
715
+ // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
716
+ utils.toDashed = function( str ) {
717
+ return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
718
+ return $1 + '-' + $2;
719
+ }).toLowerCase();
720
+ };
721
+
722
+ var console = window.console;
723
+ /**
724
+ * allow user to initialize classes via [data-namespace] or .js-namespace class
725
+ * htmlInit( Widget, 'widgetName' )
726
+ * options are parsed from data-namespace-options
727
+ */
728
+ utils.htmlInit = function( WidgetClass, namespace ) {
729
+ utils.docReady( function() {
730
+ var dashedNamespace = utils.toDashed( namespace );
731
+ var dataAttr = 'data-' + dashedNamespace;
732
+ var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
733
+ var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
734
+ var elems = utils.makeArray( dataAttrElems )
735
+ .concat( utils.makeArray( jsDashElems ) );
736
+ var dataOptionsAttr = dataAttr + '-options';
737
+ var jQuery = window.jQuery;
738
+
739
+ elems.forEach( function( elem ) {
740
+ var attr = elem.getAttribute( dataAttr ) ||
741
+ elem.getAttribute( dataOptionsAttr );
742
+ var options;
743
+ try {
744
+ options = attr && JSON.parse( attr );
745
+ } catch ( error ) {
746
+ // log error, do not initialize
747
+ if ( console ) {
748
+ console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
749
+ ': ' + error );
750
+ }
751
+ return;
752
+ }
753
+ // initialize
754
+ var instance = new WidgetClass( elem, options );
755
+ // make available via $().data('namespace')
756
+ if ( jQuery ) {
757
+ jQuery.data( elem, namespace, instance );
758
+ }
759
+ });
760
+
761
+ });
762
+ };
763
+
764
+ // ----- ----- //
765
+
766
+ return utils;
767
+
768
+ }));
769
+
770
+ /**
771
+ * Outlayer Item
772
+ */
773
+
774
+ ( function( window, factory ) {
775
+ // universal module definition
776
+ /* jshint strict: false */ /* globals define, module, require */
777
+ if ( typeof define == 'function' && define.amd ) {
778
+ // AMD - RequireJS
779
+ define( 'outlayer/item',[
780
+ 'ev-emitter/ev-emitter',
781
+ 'get-size/get-size'
782
+ ],
783
+ factory
784
+ );
785
+ } else if ( typeof module == 'object' && module.exports ) {
786
+ // CommonJS - Browserify, Webpack
787
+ module.exports = factory(
788
+ require('ev-emitter'),
789
+ require('get-size')
790
+ );
791
+ } else {
792
+ // browser global
793
+ window.Outlayer = {};
794
+ window.Outlayer.Item = factory(
795
+ window.EvEmitter,
796
+ window.getSize
797
+ );
798
+ }
799
+
800
+ }( window, function factory( EvEmitter, getSize ) {
801
+ 'use strict';
802
+
803
+ // ----- helpers ----- //
804
+
805
+ function isEmptyObj( obj ) {
806
+ for ( var prop in obj ) {
807
+ return false;
808
+ }
809
+ prop = null;
810
+ return true;
811
+ }
812
+
813
+ // -------------------------- CSS3 support -------------------------- //
814
+
815
+
816
+ var docElemStyle = document.documentElement.style;
817
+
818
+ var transitionProperty = typeof docElemStyle.transition == 'string' ?
819
+ 'transition' : 'WebkitTransition';
820
+ var transformProperty = typeof docElemStyle.transform == 'string' ?
821
+ 'transform' : 'WebkitTransform';
822
+
823
+ var transitionEndEvent = {
824
+ WebkitTransition: 'webkitTransitionEnd',
825
+ transition: 'transitionend'
826
+ }[ transitionProperty ];
827
+
828
+ // cache all vendor properties that could have vendor prefix
829
+ var vendorProperties = {
830
+ transform: transformProperty,
831
+ transition: transitionProperty,
832
+ transitionDuration: transitionProperty + 'Duration',
833
+ transitionProperty: transitionProperty + 'Property',
834
+ transitionDelay: transitionProperty + 'Delay'
835
+ };
836
+
837
+ // -------------------------- Item -------------------------- //
838
+
839
+ function Item( element, layout ) {
840
+ if ( !element ) {
841
+ return;
842
+ }
843
+
844
+ this.element = element;
845
+ // parent layout class, i.e. Masonry, Isotope, or Packery
846
+ this.layout = layout;
847
+ this.position = {
848
+ x: 0,
849
+ y: 0
850
+ };
851
+
852
+ this._create();
853
+ }
854
+
855
+ // inherit EvEmitter
856
+ var proto = Item.prototype = Object.create( EvEmitter.prototype );
857
+ proto.constructor = Item;
858
+
859
+ proto._create = function() {
860
+ // transition objects
861
+ this._transn = {
862
+ ingProperties: {},
863
+ clean: {},
864
+ onEnd: {}
865
+ };
866
+
867
+ this.css({
868
+ position: 'absolute'
869
+ });
870
+ };
871
+
872
+ // trigger specified handler for event type
873
+ proto.handleEvent = function( event ) {
874
+ var method = 'on' + event.type;
875
+ if ( this[ method ] ) {
876
+ this[ method ]( event );
877
+ }
878
+ };
879
+
880
+ proto.getSize = function() {
881
+ this.size = getSize( this.element );
882
+ };
883
+
884
+ /**
885
+ * apply CSS styles to element
886
+ * @param {Object} style
887
+ */
888
+ proto.css = function( style ) {
889
+ var elemStyle = this.element.style;
890
+
891
+ for ( var prop in style ) {
892
+ // use vendor property if available
893
+ var supportedProp = vendorProperties[ prop ] || prop;
894
+ elemStyle[ supportedProp ] = style[ prop ];
895
+ }
896
+ };
897
+
898
+ // measure position, and sets it
899
+ proto.getPosition = function() {
900
+ var style = getComputedStyle( this.element );
901
+ var isOriginLeft = this.layout._getOption('originLeft');
902
+ var isOriginTop = this.layout._getOption('originTop');
903
+ var xValue = style[ isOriginLeft ? 'left' : 'right' ];
904
+ var yValue = style[ isOriginTop ? 'top' : 'bottom' ];
905
+ var x = parseFloat( xValue );
906
+ var y = parseFloat( yValue );
907
+ // convert percent to pixels
908
+ var layoutSize = this.layout.size;
909
+ if ( xValue.indexOf('%') != -1 ) {
910
+ x = ( x / 100 ) * layoutSize.width;
911
+ }
912
+ if ( yValue.indexOf('%') != -1 ) {
913
+ y = ( y / 100 ) * layoutSize.height;
914
+ }
915
+ // clean up 'auto' or other non-integer values
916
+ x = isNaN( x ) ? 0 : x;
917
+ y = isNaN( y ) ? 0 : y;
918
+ // remove padding from measurement
919
+ x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;
920
+ y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;
921
+
922
+ this.position.x = x;
923
+ this.position.y = y;
924
+ };
925
+
926
+ // set settled position, apply padding
927
+ proto.layoutPosition = function() {
928
+ var layoutSize = this.layout.size;
929
+ var style = {};
930
+ var isOriginLeft = this.layout._getOption('originLeft');
931
+ var isOriginTop = this.layout._getOption('originTop');
932
+
933
+ // x
934
+ var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';
935
+ var xProperty = isOriginLeft ? 'left' : 'right';
936
+ var xResetProperty = isOriginLeft ? 'right' : 'left';
937
+
938
+ var x = this.position.x + layoutSize[ xPadding ];
939
+ // set in percentage or pixels
940
+ style[ xProperty ] = this.getXValue( x );
941
+ // reset other property
942
+ style[ xResetProperty ] = '';
943
+
944
+ // y
945
+ var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';
946
+ var yProperty = isOriginTop ? 'top' : 'bottom';
947
+ var yResetProperty = isOriginTop ? 'bottom' : 'top';
948
+
949
+ var y = this.position.y + layoutSize[ yPadding ];
950
+ // set in percentage or pixels
951
+ style[ yProperty ] = this.getYValue( y );
952
+ // reset other property
953
+ style[ yResetProperty ] = '';
954
+
955
+ this.css( style );
956
+ this.emitEvent( 'layout', [ this ] );
957
+ };
958
+
959
+ proto.getXValue = function( x ) {
960
+ var isHorizontal = this.layout._getOption('horizontal');
961
+ return this.layout.options.percentPosition && !isHorizontal ?
962
+ ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';
963
+ };
964
+
965
+ proto.getYValue = function( y ) {
966
+ var isHorizontal = this.layout._getOption('horizontal');
967
+ return this.layout.options.percentPosition && isHorizontal ?
968
+ ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';
969
+ };
970
+
971
+ proto._transitionTo = function( x, y ) {
972
+ this.getPosition();
973
+ // get current x & y from top/left
974
+ var curX = this.position.x;
975
+ var curY = this.position.y;
976
+
977
+ var didNotMove = x == this.position.x && y == this.position.y;
978
+
979
+ // save end position
980
+ this.setPosition( x, y );
981
+
982
+ // if did not move and not transitioning, just go to layout
983
+ if ( didNotMove && !this.isTransitioning ) {
984
+ this.layoutPosition();
985
+ return;
986
+ }
987
+
988
+ var transX = x - curX;
989
+ var transY = y - curY;
990
+ var transitionStyle = {};
991
+ transitionStyle.transform = this.getTranslate( transX, transY );
992
+
993
+ this.transition({
994
+ to: transitionStyle,
995
+ onTransitionEnd: {
996
+ transform: this.layoutPosition
997
+ },
998
+ isCleaning: true
999
+ });
1000
+ };
1001
+
1002
+ proto.getTranslate = function( x, y ) {
1003
+ // flip cooridinates if origin on right or bottom
1004
+ var isOriginLeft = this.layout._getOption('originLeft');
1005
+ var isOriginTop = this.layout._getOption('originTop');
1006
+ x = isOriginLeft ? x : -x;
1007
+ y = isOriginTop ? y : -y;
1008
+ return 'translate3d(' + x + 'px, ' + y + 'px, 0)';
1009
+ };
1010
+
1011
+ // non transition + transform support
1012
+ proto.goTo = function( x, y ) {
1013
+ this.setPosition( x, y );
1014
+ this.layoutPosition();
1015
+ };
1016
+
1017
+ proto.moveTo = proto._transitionTo;
1018
+
1019
+ proto.setPosition = function( x, y ) {
1020
+ this.position.x = parseFloat( x );
1021
+ this.position.y = parseFloat( y );
1022
+ };
1023
+
1024
+ // ----- transition ----- //
1025
+
1026
+ /**
1027
+ * @param {Object} style - CSS
1028
+ * @param {Function} onTransitionEnd
1029
+ */
1030
+
1031
+ // non transition, just trigger callback
1032
+ proto._nonTransition = function( args ) {
1033
+ this.css( args.to );
1034
+ if ( args.isCleaning ) {
1035
+ this._removeStyles( args.to );
1036
+ }
1037
+ for ( var prop in args.onTransitionEnd ) {
1038
+ args.onTransitionEnd[ prop ].call( this );
1039
+ }
1040
+ };
1041
+
1042
+ /**
1043
+ * proper transition
1044
+ * @param {Object} args - arguments
1045
+ * @param {Object} to - style to transition to
1046
+ * @param {Object} from - style to start transition from
1047
+ * @param {Boolean} isCleaning - removes transition styles after transition
1048
+ * @param {Function} onTransitionEnd - callback
1049
+ */
1050
+ proto.transition = function( args ) {
1051
+ // redirect to nonTransition if no transition duration
1052
+ if ( !parseFloat( this.layout.options.transitionDuration ) ) {
1053
+ this._nonTransition( args );
1054
+ return;
1055
+ }
1056
+
1057
+ var _transition = this._transn;
1058
+ // keep track of onTransitionEnd callback by css property
1059
+ for ( var prop in args.onTransitionEnd ) {
1060
+ _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];
1061
+ }
1062
+ // keep track of properties that are transitioning
1063
+ for ( prop in args.to ) {
1064
+ _transition.ingProperties[ prop ] = true;
1065
+ // keep track of properties to clean up when transition is done
1066
+ if ( args.isCleaning ) {
1067
+ _transition.clean[ prop ] = true;
1068
+ }
1069
+ }
1070
+
1071
+ // set from styles
1072
+ if ( args.from ) {
1073
+ this.css( args.from );
1074
+ // force redraw. http://blog.alexmaccaw.com/css-transitions
1075
+ var h = this.element.offsetHeight;
1076
+ // hack for JSHint to hush about unused var
1077
+ h = null;
1078
+ }
1079
+ // enable transition
1080
+ this.enableTransition( args.to );
1081
+ // set styles that are transitioning
1082
+ this.css( args.to );
1083
+
1084
+ this.isTransitioning = true;
1085
+
1086
+ };
1087
+
1088
+ // dash before all cap letters, including first for
1089
+ // WebkitTransform => -webkit-transform
1090
+ function toDashedAll( str ) {
1091
+ return str.replace( /([A-Z])/g, function( $1 ) {
1092
+ return '-' + $1.toLowerCase();
1093
+ });
1094
+ }
1095
+
1096
+ var transitionProps = 'opacity,' + toDashedAll( transformProperty );
1097
+
1098
+ proto.enableTransition = function(/* style */) {
1099
+ // HACK changing transitionProperty during a transition
1100
+ // will cause transition to jump
1101
+ if ( this.isTransitioning ) {
1102
+ return;
1103
+ }
1104
+
1105
+ // make `transition: foo, bar, baz` from style object
1106
+ // HACK un-comment this when enableTransition can work
1107
+ // while a transition is happening
1108
+ // var transitionValues = [];
1109
+ // for ( var prop in style ) {
1110
+ // // dash-ify camelCased properties like WebkitTransition
1111
+ // prop = vendorProperties[ prop ] || prop;
1112
+ // transitionValues.push( toDashedAll( prop ) );
1113
+ // }
1114
+ // munge number to millisecond, to match stagger
1115
+ var duration = this.layout.options.transitionDuration;
1116
+ duration = typeof duration == 'number' ? duration + 'ms' : duration;
1117
+ // enable transition styles
1118
+ this.css({
1119
+ transitionProperty: transitionProps,
1120
+ transitionDuration: duration,
1121
+ transitionDelay: this.staggerDelay || 0
1122
+ });
1123
+ // listen for transition end event
1124
+ this.element.addEventListener( transitionEndEvent, this, false );
1125
+ };
1126
+
1127
+ // ----- events ----- //
1128
+
1129
+ proto.onwebkitTransitionEnd = function( event ) {
1130
+ this.ontransitionend( event );
1131
+ };
1132
+
1133
+ proto.onotransitionend = function( event ) {
1134
+ this.ontransitionend( event );
1135
+ };
1136
+
1137
+ // properties that I munge to make my life easier
1138
+ var dashedVendorProperties = {
1139
+ '-webkit-transform': 'transform'
1140
+ };
1141
+
1142
+ proto.ontransitionend = function( event ) {
1143
+ // disregard bubbled events from children
1144
+ if ( event.target !== this.element ) {
1145
+ return;
1146
+ }
1147
+ var _transition = this._transn;
1148
+ // get property name of transitioned property, convert to prefix-free
1149
+ var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;
1150
+
1151
+ // remove property that has completed transitioning
1152
+ delete _transition.ingProperties[ propertyName ];
1153
+ // check if any properties are still transitioning
1154
+ if ( isEmptyObj( _transition.ingProperties ) ) {
1155
+ // all properties have completed transitioning
1156
+ this.disableTransition();
1157
+ }
1158
+ // clean style
1159
+ if ( propertyName in _transition.clean ) {
1160
+ // clean up style
1161
+ this.element.style[ event.propertyName ] = '';
1162
+ delete _transition.clean[ propertyName ];
1163
+ }
1164
+ // trigger onTransitionEnd callback
1165
+ if ( propertyName in _transition.onEnd ) {
1166
+ var onTransitionEnd = _transition.onEnd[ propertyName ];
1167
+ onTransitionEnd.call( this );
1168
+ delete _transition.onEnd[ propertyName ];
1169
+ }
1170
+
1171
+ this.emitEvent( 'transitionEnd', [ this ] );
1172
+ };
1173
+
1174
+ proto.disableTransition = function() {
1175
+ this.removeTransitionStyles();
1176
+ this.element.removeEventListener( transitionEndEvent, this, false );
1177
+ this.isTransitioning = false;
1178
+ };
1179
+
1180
+ /**
1181
+ * removes style property from element
1182
+ * @param {Object} style
1183
+ **/
1184
+ proto._removeStyles = function( style ) {
1185
+ // clean up transition styles
1186
+ var cleanStyle = {};
1187
+ for ( var prop in style ) {
1188
+ cleanStyle[ prop ] = '';
1189
+ }
1190
+ this.css( cleanStyle );
1191
+ };
1192
+
1193
+ var cleanTransitionStyle = {
1194
+ transitionProperty: '',
1195
+ transitionDuration: '',
1196
+ transitionDelay: ''
1197
+ };
1198
+
1199
+ proto.removeTransitionStyles = function() {
1200
+ // remove transition
1201
+ this.css( cleanTransitionStyle );
1202
+ };
1203
+
1204
+ // ----- stagger ----- //
1205
+
1206
+ proto.stagger = function( delay ) {
1207
+ delay = isNaN( delay ) ? 0 : delay;
1208
+ this.staggerDelay = delay + 'ms';
1209
+ };
1210
+
1211
+ // ----- show/hide/remove ----- //
1212
+
1213
+ // remove element from DOM
1214
+ proto.removeElem = function() {
1215
+ this.element.parentNode.removeChild( this.element );
1216
+ // remove display: none
1217
+ this.css({ display: '' });
1218
+ this.emitEvent( 'remove', [ this ] );
1219
+ };
1220
+
1221
+ proto.remove = function() {
1222
+ // just remove element if no transition support or no transition
1223
+ if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {
1224
+ this.removeElem();
1225
+ return;
1226
+ }
1227
+
1228
+ // start transition
1229
+ this.once( 'transitionEnd', function() {
1230
+ this.removeElem();
1231
+ });
1232
+ this.hide();
1233
+ };
1234
+
1235
+ proto.reveal = function() {
1236
+ delete this.isHidden;
1237
+ // remove display: none
1238
+ this.css({ display: '' });
1239
+
1240
+ var options = this.layout.options;
1241
+
1242
+ var onTransitionEnd = {};
1243
+ var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');
1244
+ onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;
1245
+
1246
+ this.transition({
1247
+ from: options.hiddenStyle,
1248
+ to: options.visibleStyle,
1249
+ isCleaning: true,
1250
+ onTransitionEnd: onTransitionEnd
1251
+ });
1252
+ };
1253
+
1254
+ proto.onRevealTransitionEnd = function() {
1255
+ // check if still visible
1256
+ // during transition, item may have been hidden
1257
+ if ( !this.isHidden ) {
1258
+ this.emitEvent('reveal');
1259
+ }
1260
+ };
1261
+
1262
+ /**
1263
+ * get style property use for hide/reveal transition end
1264
+ * @param {String} styleProperty - hiddenStyle/visibleStyle
1265
+ * @returns {String}
1266
+ */
1267
+ proto.getHideRevealTransitionEndProperty = function( styleProperty ) {
1268
+ var optionStyle = this.layout.options[ styleProperty ];
1269
+ // use opacity
1270
+ if ( optionStyle.opacity ) {
1271
+ return 'opacity';
1272
+ }
1273
+ // get first property
1274
+ for ( var prop in optionStyle ) {
1275
+ return prop;
1276
+ }
1277
+ };
1278
+
1279
+ proto.hide = function() {
1280
+ // set flag
1281
+ this.isHidden = true;
1282
+ // remove display: none
1283
+ this.css({ display: '' });
1284
+
1285
+ var options = this.layout.options;
1286
+
1287
+ var onTransitionEnd = {};
1288
+ var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');
1289
+ onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;
1290
+
1291
+ this.transition({
1292
+ from: options.visibleStyle,
1293
+ to: options.hiddenStyle,
1294
+ // keep hidden stuff hidden
1295
+ isCleaning: true,
1296
+ onTransitionEnd: onTransitionEnd
1297
+ });
1298
+ };
1299
+
1300
+ proto.onHideTransitionEnd = function() {
1301
+ // check if still hidden
1302
+ // during transition, item may have been un-hidden
1303
+ if ( this.isHidden ) {
1304
+ this.css({ display: 'none' });
1305
+ this.emitEvent('hide');
1306
+ }
1307
+ };
1308
+
1309
+ proto.destroy = function() {
1310
+ this.css({
1311
+ position: '',
1312
+ left: '',
1313
+ right: '',
1314
+ top: '',
1315
+ bottom: '',
1316
+ transition: '',
1317
+ transform: ''
1318
+ });
1319
+ };
1320
+
1321
+ return Item;
1322
+
1323
+ }));
1324
+
1325
+ /*!
1326
+ * Outlayer v2.1.1
1327
+ * the brains and guts of a layout library
1328
+ * MIT license
1329
+ */
1330
+
1331
+ ( function( window, factory ) {
1332
+ 'use strict';
1333
+ // universal module definition
1334
+ /* jshint strict: false */ /* globals define, module, require */
1335
+ if ( typeof define == 'function' && define.amd ) {
1336
+ // AMD - RequireJS
1337
+ define( 'outlayer/outlayer',[
1338
+ 'ev-emitter/ev-emitter',
1339
+ 'get-size/get-size',
1340
+ 'fizzy-ui-utils/utils',
1341
+ './item'
1342
+ ],
1343
+ function( EvEmitter, getSize, utils, Item ) {
1344
+ return factory( window, EvEmitter, getSize, utils, Item);
1345
+ }
1346
+ );
1347
+ } else if ( typeof module == 'object' && module.exports ) {
1348
+ // CommonJS - Browserify, Webpack
1349
+ module.exports = factory(
1350
+ window,
1351
+ require('ev-emitter'),
1352
+ require('get-size'),
1353
+ require('fizzy-ui-utils'),
1354
+ require('./item')
1355
+ );
1356
+ } else {
1357
+ // browser global
1358
+ window.Outlayer = factory(
1359
+ window,
1360
+ window.EvEmitter,
1361
+ window.getSize,
1362
+ window.fizzyUIUtils,
1363
+ window.Outlayer.Item
1364
+ );
1365
+ }
1366
+
1367
+ }( window, function factory( window, EvEmitter, getSize, utils, Item ) {
1368
+ 'use strict';
1369
+
1370
+ // ----- vars ----- //
1371
+
1372
+ var console = window.console;
1373
+ var jQuery = window.jQuery;
1374
+ var noop = function() {};
1375
+
1376
+ // -------------------------- Outlayer -------------------------- //
1377
+
1378
+ // globally unique identifiers
1379
+ var GUID = 0;
1380
+ // internal store of all Outlayer intances
1381
+ var instances = {};
1382
+
1383
+
1384
+ /**
1385
+ * @param {Element, String} element
1386
+ * @param {Object} options
1387
+ * @constructor
1388
+ */
1389
+ function Outlayer( element, options ) {
1390
+ var queryElement = utils.getQueryElement( element );
1391
+ if ( !queryElement ) {
1392
+ if ( console ) {
1393
+ console.error( 'Bad element for ' + this.constructor.namespace +
1394
+ ': ' + ( queryElement || element ) );
1395
+ }
1396
+ return;
1397
+ }
1398
+ this.element = queryElement;
1399
+ // add jQuery
1400
+ if ( jQuery ) {
1401
+ this.$element = jQuery( this.element );
1402
+ }
1403
+
1404
+ // options
1405
+ this.options = utils.extend( {}, this.constructor.defaults );
1406
+ this.option( options );
1407
+
1408
+ // add id for Outlayer.getFromElement
1409
+ var id = ++GUID;
1410
+ this.element.outlayerGUID = id; // expando
1411
+ instances[ id ] = this; // associate via id
1412
+
1413
+ // kick it off
1414
+ this._create();
1415
+
1416
+ var isInitLayout = this._getOption('initLayout');
1417
+ if ( isInitLayout ) {
1418
+ this.layout();
1419
+ }
1420
+ }
1421
+
1422
+ // settings are for internal use only
1423
+ Outlayer.namespace = 'outlayer';
1424
+ Outlayer.Item = Item;
1425
+
1426
+ // default options
1427
+ Outlayer.defaults = {
1428
+ containerStyle: {
1429
+ position: 'relative'
1430
+ },
1431
+ initLayout: true,
1432
+ originLeft: true,
1433
+ originTop: true,
1434
+ resize: true,
1435
+ resizeContainer: true,
1436
+ // item options
1437
+ transitionDuration: '0.4s',
1438
+ hiddenStyle: {
1439
+ opacity: 0,
1440
+ transform: 'scale(0.001)'
1441
+ },
1442
+ visibleStyle: {
1443
+ opacity: 1,
1444
+ transform: 'scale(1)'
1445
+ }
1446
+ };
1447
+
1448
+ var proto = Outlayer.prototype;
1449
+ // inherit EvEmitter
1450
+ utils.extend( proto, EvEmitter.prototype );
1451
+
1452
+ /**
1453
+ * set options
1454
+ * @param {Object} opts
1455
+ */
1456
+ proto.option = function( opts ) {
1457
+ utils.extend( this.options, opts );
1458
+ };
1459
+
1460
+ /**
1461
+ * get backwards compatible option value, check old name
1462
+ */
1463
+ proto._getOption = function( option ) {
1464
+ var oldOption = this.constructor.compatOptions[ option ];
1465
+ return oldOption && this.options[ oldOption ] !== undefined ?
1466
+ this.options[ oldOption ] : this.options[ option ];
1467
+ };
1468
+
1469
+ Outlayer.compatOptions = {
1470
+ // currentName: oldName
1471
+ initLayout: 'isInitLayout',
1472
+ horizontal: 'isHorizontal',
1473
+ layoutInstant: 'isLayoutInstant',
1474
+ originLeft: 'isOriginLeft',
1475
+ originTop: 'isOriginTop',
1476
+ resize: 'isResizeBound',
1477
+ resizeContainer: 'isResizingContainer'
1478
+ };
1479
+
1480
+ proto._create = function() {
1481
+ // get items from children
1482
+ this.reloadItems();
1483
+ // elements that affect layout, but are not laid out
1484
+ this.stamps = [];
1485
+ this.stamp( this.options.stamp );
1486
+ // set container style
1487
+ utils.extend( this.element.style, this.options.containerStyle );
1488
+
1489
+ // bind resize method
1490
+ var canBindResize = this._getOption('resize');
1491
+ if ( canBindResize ) {
1492
+ this.bindResize();
1493
+ }
1494
+ };
1495
+
1496
+ // goes through all children again and gets bricks in proper order
1497
+ proto.reloadItems = function() {
1498
+ // collection of item elements
1499
+ this.items = this._itemize( this.element.children );
1500
+ };
1501
+
1502
+
1503
+ /**
1504
+ * turn elements into Outlayer.Items to be used in layout
1505
+ * @param {Array or NodeList or HTMLElement} elems
1506
+ * @returns {Array} items - collection of new Outlayer Items
1507
+ */
1508
+ proto._itemize = function( elems ) {
1509
+
1510
+ var itemElems = this._filterFindItemElements( elems );
1511
+ var Item = this.constructor.Item;
1512
+
1513
+ // create new Outlayer Items for collection
1514
+ var items = [];
1515
+ for ( var i=0; i < itemElems.length; i++ ) {
1516
+ var elem = itemElems[i];
1517
+ var item = new Item( elem, this );
1518
+ items.push( item );
1519
+ }
1520
+
1521
+ return items;
1522
+ };
1523
+
1524
+ /**
1525
+ * get item elements to be used in layout
1526
+ * @param {Array or NodeList or HTMLElement} elems
1527
+ * @returns {Array} items - item elements
1528
+ */
1529
+ proto._filterFindItemElements = function( elems ) {
1530
+ return utils.filterFindElements( elems, this.options.itemSelector );
1531
+ };
1532
+
1533
+ /**
1534
+ * getter method for getting item elements
1535
+ * @returns {Array} elems - collection of item elements
1536
+ */
1537
+ proto.getItemElements = function() {
1538
+ return this.items.map( function( item ) {
1539
+ return item.element;
1540
+ });
1541
+ };
1542
+
1543
+ // ----- init & layout ----- //
1544
+
1545
+ /**
1546
+ * lays out all items
1547
+ */
1548
+ proto.layout = function() {
1549
+ this._resetLayout();
1550
+ this._manageStamps();
1551
+
1552
+ // don't animate first layout
1553
+ var layoutInstant = this._getOption('layoutInstant');
1554
+ var isInstant = layoutInstant !== undefined ?
1555
+ layoutInstant : !this._isLayoutInited;
1556
+ this.layoutItems( this.items, isInstant );
1557
+
1558
+ // flag for initalized
1559
+ this._isLayoutInited = true;
1560
+ };
1561
+
1562
+ // _init is alias for layout
1563
+ proto._init = proto.layout;
1564
+
1565
+ /**
1566
+ * logic before any new layout
1567
+ */
1568
+ proto._resetLayout = function() {
1569
+ this.getSize();
1570
+ };
1571
+
1572
+
1573
+ proto.getSize = function() {
1574
+ this.size = getSize( this.element );
1575
+ };
1576
+
1577
+ /**
1578
+ * get measurement from option, for columnWidth, rowHeight, gutter
1579
+ * if option is String -> get element from selector string, & get size of element
1580
+ * if option is Element -> get size of element
1581
+ * else use option as a number
1582
+ *
1583
+ * @param {String} measurement
1584
+ * @param {String} size - width or height
1585
+ * @private
1586
+ */
1587
+ proto._getMeasurement = function( measurement, size ) {
1588
+ var option = this.options[ measurement ];
1589
+ var elem;
1590
+ if ( !option ) {
1591
+ // default to 0
1592
+ this[ measurement ] = 0;
1593
+ } else {
1594
+ // use option as an element
1595
+ if ( typeof option == 'string' ) {
1596
+ elem = this.element.querySelector( option );
1597
+ } else if ( option instanceof HTMLElement ) {
1598
+ elem = option;
1599
+ }
1600
+ // use size of element, if element
1601
+ this[ measurement ] = elem ? getSize( elem )[ size ] : option;
1602
+ }
1603
+ };
1604
+
1605
+ /**
1606
+ * layout a collection of item elements
1607
+ * @api public
1608
+ */
1609
+ proto.layoutItems = function( items, isInstant ) {
1610
+ items = this._getItemsForLayout( items );
1611
+
1612
+ this._layoutItems( items, isInstant );
1613
+
1614
+ this._postLayout();
1615
+ };
1616
+
1617
+ /**
1618
+ * get the items to be laid out
1619
+ * you may want to skip over some items
1620
+ * @param {Array} items
1621
+ * @returns {Array} items
1622
+ */
1623
+ proto._getItemsForLayout = function( items ) {
1624
+ return items.filter( function( item ) {
1625
+ return !item.isIgnored;
1626
+ });
1627
+ };
1628
+
1629
+ /**
1630
+ * layout items
1631
+ * @param {Array} items
1632
+ * @param {Boolean} isInstant
1633
+ */
1634
+ proto._layoutItems = function( items, isInstant ) {
1635
+ this._emitCompleteOnItems( 'layout', items );
1636
+
1637
+ if ( !items || !items.length ) {
1638
+ // no items, emit event with empty array
1639
+ return;
1640
+ }
1641
+
1642
+ var queue = [];
1643
+
1644
+ items.forEach( function( item ) {
1645
+ // get x/y object from method
1646
+ var position = this._getItemLayoutPosition( item );
1647
+ // enqueue
1648
+ position.item = item;
1649
+ position.isInstant = isInstant || item.isLayoutInstant;
1650
+ queue.push( position );
1651
+ }, this );
1652
+
1653
+ this._processLayoutQueue( queue );
1654
+ };
1655
+
1656
+ /**
1657
+ * get item layout position
1658
+ * @param {Outlayer.Item} item
1659
+ * @returns {Object} x and y position
1660
+ */
1661
+ proto._getItemLayoutPosition = function( /* item */ ) {
1662
+ return {
1663
+ x: 0,
1664
+ y: 0
1665
+ };
1666
+ };
1667
+
1668
+ /**
1669
+ * iterate over array and position each item
1670
+ * Reason being - separating this logic prevents 'layout invalidation'
1671
+ * thx @paul_irish
1672
+ * @param {Array} queue
1673
+ */
1674
+ proto._processLayoutQueue = function( queue ) {
1675
+ this.updateStagger();
1676
+ queue.forEach( function( obj, i ) {
1677
+ this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );
1678
+ }, this );
1679
+ };
1680
+
1681
+ // set stagger from option in milliseconds number
1682
+ proto.updateStagger = function() {
1683
+ var stagger = this.options.stagger;
1684
+ if ( stagger === null || stagger === undefined ) {
1685
+ this.stagger = 0;
1686
+ return;
1687
+ }
1688
+ this.stagger = getMilliseconds( stagger );
1689
+ return this.stagger;
1690
+ };
1691
+
1692
+ /**
1693
+ * Sets position of item in DOM
1694
+ * @param {Outlayer.Item} item
1695
+ * @param {Number} x - horizontal position
1696
+ * @param {Number} y - vertical position
1697
+ * @param {Boolean} isInstant - disables transitions
1698
+ */
1699
+ proto._positionItem = function( item, x, y, isInstant, i ) {
1700
+ if ( isInstant ) {
1701
+ // if not transition, just set CSS
1702
+ item.goTo( x, y );
1703
+ } else {
1704
+ item.stagger( i * this.stagger );
1705
+ item.moveTo( x, y );
1706
+ }
1707
+ };
1708
+
1709
+ /**
1710
+ * Any logic you want to do after each layout,
1711
+ * i.e. size the container
1712
+ */
1713
+ proto._postLayout = function() {
1714
+ this.resizeContainer();
1715
+ };
1716
+
1717
+ proto.resizeContainer = function() {
1718
+ var isResizingContainer = this._getOption('resizeContainer');
1719
+ if ( !isResizingContainer ) {
1720
+ return;
1721
+ }
1722
+ var size = this._getContainerSize();
1723
+ if ( size ) {
1724
+ this._setContainerMeasure( size.width, true );
1725
+ this._setContainerMeasure( size.height, false );
1726
+ }
1727
+ };
1728
+
1729
+ /**
1730
+ * Sets width or height of container if returned
1731
+ * @returns {Object} size
1732
+ * @param {Number} width
1733
+ * @param {Number} height
1734
+ */
1735
+ proto._getContainerSize = noop;
1736
+
1737
+ /**
1738
+ * @param {Number} measure - size of width or height
1739
+ * @param {Boolean} isWidth
1740
+ */
1741
+ proto._setContainerMeasure = function( measure, isWidth ) {
1742
+ if ( measure === undefined ) {
1743
+ return;
1744
+ }
1745
+
1746
+ var elemSize = this.size;
1747
+ // add padding and border width if border box
1748
+ if ( elemSize.isBorderBox ) {
1749
+ measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
1750
+ elemSize.borderLeftWidth + elemSize.borderRightWidth :
1751
+ elemSize.paddingBottom + elemSize.paddingTop +
1752
+ elemSize.borderTopWidth + elemSize.borderBottomWidth;
1753
+ }
1754
+
1755
+ measure = Math.max( measure, 0 );
1756
+ this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
1757
+ };
1758
+
1759
+ /**
1760
+ * emit eventComplete on a collection of items events
1761
+ * @param {String} eventName
1762
+ * @param {Array} items - Outlayer.Items
1763
+ */
1764
+ proto._emitCompleteOnItems = function( eventName, items ) {
1765
+ var _this = this;
1766
+ function onComplete() {
1767
+ _this.dispatchEvent( eventName + 'Complete', null, [ items ] );
1768
+ }
1769
+
1770
+ var count = items.length;
1771
+ if ( !items || !count ) {
1772
+ onComplete();
1773
+ return;
1774
+ }
1775
+
1776
+ var doneCount = 0;
1777
+ function tick() {
1778
+ doneCount++;
1779
+ if ( doneCount == count ) {
1780
+ onComplete();
1781
+ }
1782
+ }
1783
+
1784
+ // bind callback
1785
+ items.forEach( function( item ) {
1786
+ item.once( eventName, tick );
1787
+ });
1788
+ };
1789
+
1790
+ /**
1791
+ * emits events via EvEmitter and jQuery events
1792
+ * @param {String} type - name of event
1793
+ * @param {Event} event - original event
1794
+ * @param {Array} args - extra arguments
1795
+ */
1796
+ proto.dispatchEvent = function( type, event, args ) {
1797
+ // add original event to arguments
1798
+ var emitArgs = event ? [ event ].concat( args ) : args;
1799
+ this.emitEvent( type, emitArgs );
1800
+
1801
+ if ( jQuery ) {
1802
+ // set this.$element
1803
+ this.$element = this.$element || jQuery( this.element );
1804
+ if ( event ) {
1805
+ // create jQuery event
1806
+ var $event = jQuery.Event( event );
1807
+ $event.type = type;
1808
+ this.$element.trigger( $event, args );
1809
+ } else {
1810
+ // just trigger with type if no event available
1811
+ this.$element.trigger( type, args );
1812
+ }
1813
+ }
1814
+ };
1815
+
1816
+ // -------------------------- ignore & stamps -------------------------- //
1817
+
1818
+
1819
+ /**
1820
+ * keep item in collection, but do not lay it out
1821
+ * ignored items do not get skipped in layout
1822
+ * @param {Element} elem
1823
+ */
1824
+ proto.ignore = function( elem ) {
1825
+ var item = this.getItem( elem );
1826
+ if ( item ) {
1827
+ item.isIgnored = true;
1828
+ }
1829
+ };
1830
+
1831
+ /**
1832
+ * return item to layout collection
1833
+ * @param {Element} elem
1834
+ */
1835
+ proto.unignore = function( elem ) {
1836
+ var item = this.getItem( elem );
1837
+ if ( item ) {
1838
+ delete item.isIgnored;
1839
+ }
1840
+ };
1841
+
1842
+ /**
1843
+ * adds elements to stamps
1844
+ * @param {NodeList, Array, Element, or String} elems
1845
+ */
1846
+ proto.stamp = function( elems ) {
1847
+ elems = this._find( elems );
1848
+ if ( !elems ) {
1849
+ return;
1850
+ }
1851
+
1852
+ this.stamps = this.stamps.concat( elems );
1853
+ // ignore
1854
+ elems.forEach( this.ignore, this );
1855
+ };
1856
+
1857
+ /**
1858
+ * removes elements to stamps
1859
+ * @param {NodeList, Array, or Element} elems
1860
+ */
1861
+ proto.unstamp = function( elems ) {
1862
+ elems = this._find( elems );
1863
+ if ( !elems ){
1864
+ return;
1865
+ }
1866
+
1867
+ elems.forEach( function( elem ) {
1868
+ // filter out removed stamp elements
1869
+ utils.removeFrom( this.stamps, elem );
1870
+ this.unignore( elem );
1871
+ }, this );
1872
+ };
1873
+
1874
+ /**
1875
+ * finds child elements
1876
+ * @param {NodeList, Array, Element, or String} elems
1877
+ * @returns {Array} elems
1878
+ */
1879
+ proto._find = function( elems ) {
1880
+ if ( !elems ) {
1881
+ return;
1882
+ }
1883
+ // if string, use argument as selector string
1884
+ if ( typeof elems == 'string' ) {
1885
+ elems = this.element.querySelectorAll( elems );
1886
+ }
1887
+ elems = utils.makeArray( elems );
1888
+ return elems;
1889
+ };
1890
+
1891
+ proto._manageStamps = function() {
1892
+ if ( !this.stamps || !this.stamps.length ) {
1893
+ return;
1894
+ }
1895
+
1896
+ this._getBoundingRect();
1897
+
1898
+ this.stamps.forEach( this._manageStamp, this );
1899
+ };
1900
+
1901
+ // update boundingLeft / Top
1902
+ proto._getBoundingRect = function() {
1903
+ // get bounding rect for container element
1904
+ var boundingRect = this.element.getBoundingClientRect();
1905
+ var size = this.size;
1906
+ this._boundingRect = {
1907
+ left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,
1908
+ top: boundingRect.top + size.paddingTop + size.borderTopWidth,
1909
+ right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),
1910
+ bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )
1911
+ };
1912
+ };
1913
+
1914
+ /**
1915
+ * @param {Element} stamp
1916
+ **/
1917
+ proto._manageStamp = noop;
1918
+
1919
+ /**
1920
+ * get x/y position of element relative to container element
1921
+ * @param {Element} elem
1922
+ * @returns {Object} offset - has left, top, right, bottom
1923
+ */
1924
+ proto._getElementOffset = function( elem ) {
1925
+ var boundingRect = elem.getBoundingClientRect();
1926
+ var thisRect = this._boundingRect;
1927
+ var size = getSize( elem );
1928
+ var offset = {
1929
+ left: boundingRect.left - thisRect.left - size.marginLeft,
1930
+ top: boundingRect.top - thisRect.top - size.marginTop,
1931
+ right: thisRect.right - boundingRect.right - size.marginRight,
1932
+ bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom
1933
+ };
1934
+ return offset;
1935
+ };
1936
+
1937
+ // -------------------------- resize -------------------------- //
1938
+
1939
+ // enable event handlers for listeners
1940
+ // i.e. resize -> onresize
1941
+ proto.handleEvent = utils.handleEvent;
1942
+
1943
+ /**
1944
+ * Bind layout to window resizing
1945
+ */
1946
+ proto.bindResize = function() {
1947
+ window.addEventListener( 'resize', this );
1948
+ this.isResizeBound = true;
1949
+ };
1950
+
1951
+ /**
1952
+ * Unbind layout to window resizing
1953
+ */
1954
+ proto.unbindResize = function() {
1955
+ window.removeEventListener( 'resize', this );
1956
+ this.isResizeBound = false;
1957
+ };
1958
+
1959
+ proto.onresize = function() {
1960
+ this.resize();
1961
+ };
1962
+
1963
+ utils.debounceMethod( Outlayer, 'onresize', 100 );
1964
+
1965
+ proto.resize = function() {
1966
+ // don't trigger if size did not change
1967
+ // or if resize was unbound. See #9
1968
+ if ( !this.isResizeBound || !this.needsResizeLayout() ) {
1969
+ return;
1970
+ }
1971
+
1972
+ this.layout();
1973
+ };
1974
+
1975
+ /**
1976
+ * check if layout is needed post layout
1977
+ * @returns Boolean
1978
+ */
1979
+ proto.needsResizeLayout = function() {
1980
+ var size = getSize( this.element );
1981
+ // check that this.size and size are there
1982
+ // IE8 triggers resize on body size change, so they might not be
1983
+ var hasSizes = this.size && size;
1984
+ return hasSizes && size.innerWidth !== this.size.innerWidth;
1985
+ };
1986
+
1987
+ // -------------------------- methods -------------------------- //
1988
+
1989
+ /**
1990
+ * add items to Outlayer instance
1991
+ * @param {Array or NodeList or Element} elems
1992
+ * @returns {Array} items - Outlayer.Items
1993
+ **/
1994
+ proto.addItems = function( elems ) {
1995
+ var items = this._itemize( elems );
1996
+ // add items to collection
1997
+ if ( items.length ) {
1998
+ this.items = this.items.concat( items );
1999
+ }
2000
+ return items;
2001
+ };
2002
+
2003
+ /**
2004
+ * Layout newly-appended item elements
2005
+ * @param {Array or NodeList or Element} elems
2006
+ */
2007
+ proto.appended = function( elems ) {
2008
+ var items = this.addItems( elems );
2009
+ if ( !items.length ) {
2010
+ return;
2011
+ }
2012
+ // layout and reveal just the new items
2013
+ this.layoutItems( items, true );
2014
+ this.reveal( items );
2015
+ };
2016
+
2017
+ /**
2018
+ * Layout prepended elements
2019
+ * @param {Array or NodeList or Element} elems
2020
+ */
2021
+ proto.prepended = function( elems ) {
2022
+ var items = this._itemize( elems );
2023
+ if ( !items.length ) {
2024
+ return;
2025
+ }
2026
+ // add items to beginning of collection
2027
+ var previousItems = this.items.slice(0);
2028
+ this.items = items.concat( previousItems );
2029
+ // start new layout
2030
+ this._resetLayout();
2031
+ this._manageStamps();
2032
+ // layout new stuff without transition
2033
+ this.layoutItems( items, true );
2034
+ this.reveal( items );
2035
+ // layout previous items
2036
+ this.layoutItems( previousItems );
2037
+ };
2038
+
2039
+ /**
2040
+ * reveal a collection of items
2041
+ * @param {Array of Outlayer.Items} items
2042
+ */
2043
+ proto.reveal = function( items ) {
2044
+ this._emitCompleteOnItems( 'reveal', items );
2045
+ if ( !items || !items.length ) {
2046
+ return;
2047
+ }
2048
+ var stagger = this.updateStagger();
2049
+ items.forEach( function( item, i ) {
2050
+ item.stagger( i * stagger );
2051
+ item.reveal();
2052
+ });
2053
+ };
2054
+
2055
+ /**
2056
+ * hide a collection of items
2057
+ * @param {Array of Outlayer.Items} items
2058
+ */
2059
+ proto.hide = function( items ) {
2060
+ this._emitCompleteOnItems( 'hide', items );
2061
+ if ( !items || !items.length ) {
2062
+ return;
2063
+ }
2064
+ var stagger = this.updateStagger();
2065
+ items.forEach( function( item, i ) {
2066
+ item.stagger( i * stagger );
2067
+ item.hide();
2068
+ });
2069
+ };
2070
+
2071
+ /**
2072
+ * reveal item elements
2073
+ * @param {Array}, {Element}, {NodeList} items
2074
+ */
2075
+ proto.revealItemElements = function( elems ) {
2076
+ var items = this.getItems( elems );
2077
+ this.reveal( items );
2078
+ };
2079
+
2080
+ /**
2081
+ * hide item elements
2082
+ * @param {Array}, {Element}, {NodeList} items
2083
+ */
2084
+ proto.hideItemElements = function( elems ) {
2085
+ var items = this.getItems( elems );
2086
+ this.hide( items );
2087
+ };
2088
+
2089
+ /**
2090
+ * get Outlayer.Item, given an Element
2091
+ * @param {Element} elem
2092
+ * @param {Function} callback
2093
+ * @returns {Outlayer.Item} item
2094
+ */
2095
+ proto.getItem = function( elem ) {
2096
+ // loop through items to get the one that matches
2097
+ for ( var i=0; i < this.items.length; i++ ) {
2098
+ var item = this.items[i];
2099
+ if ( item.element == elem ) {
2100
+ // return item
2101
+ return item;
2102
+ }
2103
+ }
2104
+ };
2105
+
2106
+ /**
2107
+ * get collection of Outlayer.Items, given Elements
2108
+ * @param {Array} elems
2109
+ * @returns {Array} items - Outlayer.Items
2110
+ */
2111
+ proto.getItems = function( elems ) {
2112
+ elems = utils.makeArray( elems );
2113
+ var items = [];
2114
+ elems.forEach( function( elem ) {
2115
+ var item = this.getItem( elem );
2116
+ if ( item ) {
2117
+ items.push( item );
2118
+ }
2119
+ }, this );
2120
+
2121
+ return items;
2122
+ };
2123
+
2124
+ /**
2125
+ * remove element(s) from instance and DOM
2126
+ * @param {Array or NodeList or Element} elems
2127
+ */
2128
+ proto.remove = function( elems ) {
2129
+ var removeItems = this.getItems( elems );
2130
+
2131
+ this._emitCompleteOnItems( 'remove', removeItems );
2132
+
2133
+ // bail if no items to remove
2134
+ if ( !removeItems || !removeItems.length ) {
2135
+ return;
2136
+ }
2137
+
2138
+ removeItems.forEach( function( item ) {
2139
+ item.remove();
2140
+ // remove item from collection
2141
+ utils.removeFrom( this.items, item );
2142
+ }, this );
2143
+ };
2144
+
2145
+ // ----- destroy ----- //
2146
+
2147
+ // remove and disable Outlayer instance
2148
+ proto.destroy = function() {
2149
+ // clean up dynamic styles
2150
+ var style = this.element.style;
2151
+ style.height = '';
2152
+ style.position = '';
2153
+ style.width = '';
2154
+ // destroy items
2155
+ this.items.forEach( function( item ) {
2156
+ item.destroy();
2157
+ });
2158
+
2159
+ this.unbindResize();
2160
+
2161
+ var id = this.element.outlayerGUID;
2162
+ delete instances[ id ]; // remove reference to instance by id
2163
+ delete this.element.outlayerGUID;
2164
+ // remove data for jQuery
2165
+ if ( jQuery ) {
2166
+ jQuery.removeData( this.element, this.constructor.namespace );
2167
+ }
2168
+
2169
+ };
2170
+
2171
+ // -------------------------- data -------------------------- //
2172
+
2173
+ /**
2174
+ * get Outlayer instance from element
2175
+ * @param {Element} elem
2176
+ * @returns {Outlayer}
2177
+ */
2178
+ Outlayer.data = function( elem ) {
2179
+ elem = utils.getQueryElement( elem );
2180
+ var id = elem && elem.outlayerGUID;
2181
+ return id && instances[ id ];
2182
+ };
2183
+
2184
+
2185
+ // -------------------------- create Outlayer class -------------------------- //
2186
+
2187
+ /**
2188
+ * create a layout class
2189
+ * @param {String} namespace
2190
+ */
2191
+ Outlayer.create = function( namespace, options ) {
2192
+ // sub-class Outlayer
2193
+ var Layout = subclass( Outlayer );
2194
+ // apply new options and compatOptions
2195
+ Layout.defaults = utils.extend( {}, Outlayer.defaults );
2196
+ utils.extend( Layout.defaults, options );
2197
+ Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions );
2198
+
2199
+ Layout.namespace = namespace;
2200
+
2201
+ Layout.data = Outlayer.data;
2202
+
2203
+ // sub-class Item
2204
+ Layout.Item = subclass( Item );
2205
+
2206
+ // -------------------------- declarative -------------------------- //
2207
+
2208
+ utils.htmlInit( Layout, namespace );
2209
+
2210
+ // -------------------------- jQuery bridge -------------------------- //
2211
+
2212
+ // make into jQuery plugin
2213
+ if ( jQuery && jQuery.bridget ) {
2214
+ jQuery.bridget( namespace, Layout );
2215
+ }
2216
+
2217
+ return Layout;
2218
+ };
2219
+
2220
+ function subclass( Parent ) {
2221
+ function SubClass() {
2222
+ Parent.apply( this, arguments );
2223
+ }
2224
+
2225
+ SubClass.prototype = Object.create( Parent.prototype );
2226
+ SubClass.prototype.constructor = SubClass;
2227
+
2228
+ return SubClass;
2229
+ }
2230
+
2231
+ // ----- helpers ----- //
2232
+
2233
+ // how many milliseconds are in each unit
2234
+ var msUnits = {
2235
+ ms: 1,
2236
+ s: 1000
2237
+ };
2238
+
2239
+ // munge time-like parameter into millisecond number
2240
+ // '0.4s' -> 40
2241
+ function getMilliseconds( time ) {
2242
+ if ( typeof time == 'number' ) {
2243
+ return time;
2244
+ }
2245
+ var matches = time.match( /(^\d*\.?\d*)(\w*)/ );
2246
+ var num = matches && matches[1];
2247
+ var unit = matches && matches[2];
2248
+ if ( !num.length ) {
2249
+ return 0;
2250
+ }
2251
+ num = parseFloat( num );
2252
+ var mult = msUnits[ unit ] || 1;
2253
+ return num * mult;
2254
+ }
2255
+
2256
+ // ----- fin ----- //
2257
+
2258
+ // back in global
2259
+ Outlayer.Item = Item;
2260
+
2261
+ return Outlayer;
2262
+
2263
+ }));
2264
+
2265
+ /*!
2266
+ * Masonry v4.2.2
2267
+ * Cascading grid layout library
2268
+ * https://masonry.desandro.com
2269
+ * MIT License
2270
+ * by David DeSandro
2271
+ */
2272
+
2273
+ ( function( window, factory ) {
2274
+ // universal module definition
2275
+ /* jshint strict: false */ /*globals define, module, require */
2276
+ if ( typeof define == 'function' && define.amd ) {
2277
+ // AMD
2278
+ define( [
2279
+ 'outlayer/outlayer',
2280
+ 'get-size/get-size'
2281
+ ],
2282
+ factory );
2283
+ } else if ( typeof module == 'object' && module.exports ) {
2284
+ // CommonJS
2285
+ module.exports = factory(
2286
+ require('outlayer'),
2287
+ require('get-size')
2288
+ );
2289
+ } else {
2290
+ // browser global
2291
+ window.Masonry = factory(
2292
+ window.Outlayer,
2293
+ window.getSize
2294
+ );
2295
+ }
2296
+
2297
+ }( window, function factory( Outlayer, getSize ) {
2298
+
2299
+
2300
+
2301
+ // -------------------------- masonryDefinition -------------------------- //
2302
+
2303
+ // create an Outlayer layout class
2304
+ var Masonry = Outlayer.create('masonry');
2305
+ // isFitWidth -> fitWidth
2306
+ Masonry.compatOptions.fitWidth = 'isFitWidth';
2307
+
2308
+ var proto = Masonry.prototype;
2309
+
2310
+ proto._resetLayout = function() {
2311
+ this.getSize();
2312
+ this._getMeasurement( 'columnWidth', 'outerWidth' );
2313
+ this._getMeasurement( 'gutter', 'outerWidth' );
2314
+ this.measureColumns();
2315
+
2316
+ // reset column Y
2317
+ this.colYs = [];
2318
+ for ( var i=0; i < this.cols; i++ ) {
2319
+ this.colYs.push( 0 );
2320
+ }
2321
+
2322
+ this.maxY = 0;
2323
+ this.horizontalColIndex = 0;
2324
+ };
2325
+
2326
+ proto.measureColumns = function() {
2327
+ this.getContainerWidth();
2328
+ // if columnWidth is 0, default to outerWidth of first item
2329
+ if ( !this.columnWidth ) {
2330
+ var firstItem = this.items[0];
2331
+ var firstItemElem = firstItem && firstItem.element;
2332
+ // columnWidth fall back to item of first element
2333
+ this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||
2334
+ // if first elem has no width, default to size of container
2335
+ this.containerWidth;
2336
+ }
2337
+
2338
+ var columnWidth = this.columnWidth += this.gutter;
2339
+
2340
+ // calculate columns
2341
+ var containerWidth = this.containerWidth + this.gutter;
2342
+ var cols = containerWidth / columnWidth;
2343
+ // fix rounding errors, typically with gutters
2344
+ var excess = columnWidth - containerWidth % columnWidth;
2345
+ // if overshoot is less than a pixel, round up, otherwise floor it
2346
+ var mathMethod = excess && excess < 1 ? 'round' : 'floor';
2347
+ cols = Math[ mathMethod ]( cols );
2348
+ this.cols = Math.max( cols, 1 );
2349
+ };
2350
+
2351
+ proto.getContainerWidth = function() {
2352
+ // container is parent if fit width
2353
+ var isFitWidth = this._getOption('fitWidth');
2354
+ var container = isFitWidth ? this.element.parentNode : this.element;
2355
+ // check that this.size and size are there
2356
+ // IE8 triggers resize on body size change, so they might not be
2357
+ var size = getSize( container );
2358
+ this.containerWidth = size && size.innerWidth;
2359
+ };
2360
+
2361
+ proto._getItemLayoutPosition = function( item ) {
2362
+ item.getSize();
2363
+ // how many columns does this brick span
2364
+ var remainder = item.size.outerWidth % this.columnWidth;
2365
+ var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
2366
+ // round if off by 1 pixel, otherwise use ceil
2367
+ var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );
2368
+ colSpan = Math.min( colSpan, this.cols );
2369
+ // use horizontal or top column position
2370
+ var colPosMethod = this.options.horizontalOrder ?
2371
+ '_getHorizontalColPosition' : '_getTopColPosition';
2372
+ var colPosition = this[ colPosMethod ]( colSpan, item );
2373
+ // position the brick
2374
+ var position = {
2375
+ x: this.columnWidth * colPosition.col,
2376
+ y: colPosition.y
2377
+ };
2378
+ // apply setHeight to necessary columns
2379
+ var setHeight = colPosition.y + item.size.outerHeight;
2380
+ var setMax = colSpan + colPosition.col;
2381
+ for ( var i = colPosition.col; i < setMax; i++ ) {
2382
+ this.colYs[i] = setHeight;
2383
+ }
2384
+
2385
+ return position;
2386
+ };
2387
+
2388
+ proto._getTopColPosition = function( colSpan ) {
2389
+ var colGroup = this._getTopColGroup( colSpan );
2390
+ // get the minimum Y value from the columns
2391
+ var minimumY = Math.min.apply( Math, colGroup );
2392
+
2393
+ return {
2394
+ col: colGroup.indexOf( minimumY ),
2395
+ y: minimumY,
2396
+ };
2397
+ };
2398
+
2399
+ /**
2400
+ * @param {Number} colSpan - number of columns the element spans
2401
+ * @returns {Array} colGroup
2402
+ */
2403
+ proto._getTopColGroup = function( colSpan ) {
2404
+ if ( colSpan < 2 ) {
2405
+ // if brick spans only one column, use all the column Ys
2406
+ return this.colYs;
2407
+ }
2408
+
2409
+ var colGroup = [];
2410
+ // how many different places could this brick fit horizontally
2411
+ var groupCount = this.cols + 1 - colSpan;
2412
+ // for each group potential horizontal position
2413
+ for ( var i = 0; i < groupCount; i++ ) {
2414
+ colGroup[i] = this._getColGroupY( i, colSpan );
2415
+ }
2416
+ return colGroup;
2417
+ };
2418
+
2419
+ proto._getColGroupY = function( col, colSpan ) {
2420
+ if ( colSpan < 2 ) {
2421
+ return this.colYs[ col ];
2422
+ }
2423
+ // make an array of colY values for that one group
2424
+ var groupColYs = this.colYs.slice( col, col + colSpan );
2425
+ // and get the max value of the array
2426
+ return Math.max.apply( Math, groupColYs );
2427
+ };
2428
+
2429
+ // get column position based on horizontal index. #873
2430
+ proto._getHorizontalColPosition = function( colSpan, item ) {
2431
+ var col = this.horizontalColIndex % this.cols;
2432
+ var isOver = colSpan > 1 && col + colSpan > this.cols;
2433
+ // shift to next row if item can't fit on current row
2434
+ col = isOver ? 0 : col;
2435
+ // don't let zero-size items take up space
2436
+ var hasSize = item.size.outerWidth && item.size.outerHeight;
2437
+ this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex;
2438
+
2439
+ return {
2440
+ col: col,
2441
+ y: this._getColGroupY( col, colSpan ),
2442
+ };
2443
+ };
2444
+
2445
+ proto._manageStamp = function( stamp ) {
2446
+ var stampSize = getSize( stamp );
2447
+ var offset = this._getElementOffset( stamp );
2448
+ // get the columns that this stamp affects
2449
+ var isOriginLeft = this._getOption('originLeft');
2450
+ var firstX = isOriginLeft ? offset.left : offset.right;
2451
+ var lastX = firstX + stampSize.outerWidth;
2452
+ var firstCol = Math.floor( firstX / this.columnWidth );
2453
+ firstCol = Math.max( 0, firstCol );
2454
+ var lastCol = Math.floor( lastX / this.columnWidth );
2455
+ // lastCol should not go over if multiple of columnWidth #425
2456
+ lastCol -= lastX % this.columnWidth ? 0 : 1;
2457
+ lastCol = Math.min( this.cols - 1, lastCol );
2458
+ // set colYs to bottom of the stamp
2459
+
2460
+ var isOriginTop = this._getOption('originTop');
2461
+ var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) +
2462
+ stampSize.outerHeight;
2463
+ for ( var i = firstCol; i <= lastCol; i++ ) {
2464
+ this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
2465
+ }
2466
+ };
2467
+
2468
+ proto._getContainerSize = function() {
2469
+ this.maxY = Math.max.apply( Math, this.colYs );
2470
+ var size = {
2471
+ height: this.maxY
2472
+ };
2473
+
2474
+ if ( this._getOption('fitWidth') ) {
2475
+ size.width = this._getContainerFitWidth();
2476
+ }
2477
+
2478
+ return size;
2479
+ };
2480
+
2481
+ proto._getContainerFitWidth = function() {
2482
+ var unusedCols = 0;
2483
+ // count unused columns
2484
+ var i = this.cols;
2485
+ while ( --i ) {
2486
+ if ( this.colYs[i] !== 0 ) {
2487
+ break;
2488
+ }
2489
+ unusedCols++;
2490
+ }
2491
+ // fit container to columns that have been used
2492
+ return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
2493
+ };
2494
+
2495
+ proto.needsResizeLayout = function() {
2496
+ var previousWidth = this.containerWidth;
2497
+ this.getContainerWidth();
2498
+ return previousWidth != this.containerWidth;
2499
+ };
2500
+
2501
+ return Masonry;
2502
+
2503
+ }));