j1-template 2022.6.2 → 2022.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/_includes/themes/j1/layouts/content_generator_news_panel_posts.html +4 -4
  3. data/_includes/themes/j1/layouts/layout_metadata_generator.html +36 -19
  4. data/_layouts/default.html +0 -5
  5. data/assets/data/banner.html +2 -2
  6. data/assets/data/mdi_icons.json +29539 -13502
  7. data/assets/data/panel.html +5 -5
  8. data/assets/themes/j1/adapter/js/masonry.js +273 -0
  9. data/assets/themes/j1/core/css/icon-fonts/mdi.css +3745 -319
  10. data/assets/themes/j1/core/css/icon-fonts/mdi.min.css +1 -1
  11. data/assets/themes/j1/core/css/themes/bootstrap/bootstrap.css +1 -3
  12. data/assets/themes/j1/core/css/themes/theme_vapor/bootstrap.css +1 -3
  13. data/assets/themes/j1/core/css/themes/unodark/bootstrap.css +7 -3
  14. data/assets/themes/j1/core/css/themes/unodark/bootstrap.min.css +1 -1
  15. data/assets/themes/j1/core/css/themes/unolight/bootstrap.css +56 -4
  16. data/assets/themes/j1/core/css/themes/unolight/bootstrap.min.css +1 -1
  17. data/assets/themes/j1/core/fonts/material_design_icons/fonts/_versions/v7.0.96/eot/materialdesignicons-webfont.eot +0 -0
  18. data/assets/themes/j1/core/fonts/material_design_icons/fonts/_versions/v7.0.96/materialdesignicons-webfont.woff +0 -0
  19. data/assets/themes/j1/core/fonts/material_design_icons/fonts/_versions/v7.0.96/materialdesignicons-webfont.woff2 +0 -0
  20. data/assets/themes/j1/core/fonts/material_design_icons/fonts/_versions/v7.0.96/preview.html +717 -0
  21. data/assets/themes/j1/core/fonts/material_design_icons/fonts/_versions/v7.0.96/ttf/materialdesignicons-webfont.ttf +0 -0
  22. data/assets/themes/j1/core/fonts/material_design_icons/fonts/eot/materialdesignicons-webfont.eot +0 -0
  23. data/assets/themes/j1/core/fonts/material_design_icons/fonts/materialdesignicons-webfont.woff +0 -0
  24. data/assets/themes/j1/core/fonts/material_design_icons/fonts/materialdesignicons-webfont.woff2 +0 -0
  25. data/assets/themes/j1/core/fonts/material_design_icons/fonts/ttf/materialdesignicons-webfont.ttf +0 -0
  26. data/assets/themes/j1/modules/masonry/LICENSE +22 -0
  27. data/assets/themes/j1/modules/masonry/README.md +84 -0
  28. data/assets/themes/j1/modules/masonry/js/masonry.pkgd.js +2503 -0
  29. data/assets/themes/j1/modules/masonry/js/masonry.pkgd.min.js +9 -0
  30. data/assets/themes/j1/modules/masterslider/css/theme/uno.css +2 -1
  31. data/assets/themes/j1/modules/masterslider/css/theme/uno.min.css +1 -81
  32. data/lib/j1/version.rb +1 -1
  33. data/lib/starter_web/Gemfile +1 -0
  34. data/lib/starter_web/README.md +5 -5
  35. data/lib/starter_web/_config.yml +1 -1
  36. data/lib/starter_web/_data/blocks/banner.yml +1 -1
  37. data/lib/starter_web/_data/j1_config.yml +1 -1
  38. data/lib/starter_web/_data/{custom → layouts/custom}/readme +0 -0
  39. data/lib/starter_web/_data/modules/defaults/masonry.yml +136 -0
  40. data/lib/starter_web/_data/modules/masonry.yml +65 -0
  41. data/lib/starter_web/_data/plugins/defaults/seo-tags.yml +2 -2
  42. data/lib/starter_web/_data/plugins/seo-tags.yml +1 -1
  43. data/lib/starter_web/_data/resources.yml +26 -3
  44. data/lib/starter_web/_data/templates/feed.xml +5 -3
  45. data/lib/starter_web/_data/templates/robots.txt +26 -0
  46. data/lib/starter_web/_data/templates/seo-tags.html +18 -0
  47. data/lib/starter_web/_data/templates/sitemap.xml +29 -0
  48. data/lib/starter_web/_plugins/index/lunr.rb +25 -3
  49. data/lib/starter_web/_plugins/seo/j1-feed.rb +11 -9
  50. data/lib/starter_web/_plugins/seo/j1-seo-tags.rb +54 -57
  51. data/lib/starter_web/_plugins/seo/j1-sitemap.rb +5 -4
  52. data/lib/starter_web/assets/images/modules/attics/1920x1280/hayden-mills-2.jpg +0 -0
  53. data/lib/starter_web/assets/images/modules/attics/ideas-start-here-1920x1280.jpg +0 -0
  54. data/lib/starter_web/assets/images/triangles-bg.png +0 -0
  55. data/lib/starter_web/package.json +1 -1
  56. data/lib/starter_web/utilsrv/_defaults/package.json +1 -1
  57. data/lib/starter_web/utilsrv/package.json +1 -1
  58. metadata +18 -9
  59. data/assets/themes/j1/core/fonts/material_design_icons/fonts/_versions/v3.3.92/eot/materialdesignicons-webfont.eot +0 -0
  60. data/assets/themes/j1/core/fonts/material_design_icons/fonts/_versions/v3.3.92/materialdesignicons-webfont.woff +0 -0
  61. data/assets/themes/j1/core/fonts/material_design_icons/fonts/_versions/v3.3.92/materialdesignicons-webfont.woff2 +0 -0
  62. data/assets/themes/j1/core/fonts/material_design_icons/fonts/_versions/v3.3.92/svg/materialdesignicons-webfont.svg +0 -10188
  63. data/assets/themes/j1/core/fonts/material_design_icons/fonts/_versions/v3.3.92/ttf/materialdesignicons-webfont.ttf +0 -0
  64. data/assets/themes/j1/core/fonts/material_design_icons/fonts/svg/materialdesignicons-webfont.svg +0 -10188
@@ -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
+ }));