Se ha producido un error al procesar la plantilla.
Failed to "?eval" string with this error:

---begin-message---
Syntax error in ?eval-ed string in line 1, column 2:
Encountered ")", but was expecting one of:
    <STRING_LITERAL>
    <RAW_STRING>
    "false"
    "true"
    <INTEGER>
    <DECIMAL>
    "."
    "+"
    "-"
    "!"
    "["
    "("
    "{"
    <ID>
---end-message---

The failing expression:
==> urlimagen?eval  [in template "20102#20129#12795723" at line 54, column 33]

----
FTL stack trace ("~" means nesting-related):
	- Failed at: ${urlimagen?eval["alt"]}  [in template "20102#20129#12795723" at line 54, column 31]
----
1<#if !entries?has_content> 
2    	<#if !themeDisplay.isSignedIn()> 
3    		${renderRequest.setAttribute("PORTLET_CONFIGURATOR_VISIBILITY", true)} 
4    	</#if> 
5     
6    	<div class="alert alert-info"> 
7    		<@liferay_ui["message"] key="there-are-no-results" /> 
8    	</div> 
9</#if> 
10     
11<#assign nameInstancePublisher = randomNamespace />   
12     
13        <div class="gallery${nameInstancePublisher}" data-flickity='{  
14            "pageDots": true,  
15            "cellAlign": "left",  
16            "freeScroll": true,  
17            "wrapAround": true, 
18            "percentPosition": false  
19        }'> 
20            <#list entries as entry> 
21                <#assign docXml = saxReaderUtil.read(entry.getAssetRenderer().getArticle().getContentByLocale(locale)) /> 
22        <#assign viewURL = renderResponse.createRenderURL() /> 
23        <#assign urlimagen = docXml.valueOf("//dynamic-element[@name='Imagenpub']")/> 
24        
25         
26         
27        <#assign titulo = docXml.valueOf("//dynamic-element[@name='IMAGEN']/dynamic-content/text()") /> 
28        <#assign resumen = docXml.valueOf("//dynamic-element[@name='Resumen']/dynamic-content/text()") /> 
29        <#assign contenido = docXml.valueOf("//dynamic-element[@name='Contenido']/dynamic-content/text()") /> 
30        <#assign color = docXml.valueOf("//dynamic-element[@name='Color']/dynamic-content/text()") /> 
31        <#assign adicional1 = docXml.valueOf("//dynamic-element[@name='Adicional1']/dynamic-content/text()") /> 
32        <#assign adicional2 = docXml.valueOf("//dynamic-element[@name='Adicional2']/dynamic-content/text()") /> 
33        <#assign autor = docXml.valueOf("//dynamic-element[@name='Autor']/dynamic-content/text()") /> 
34        <#assign linkext = docXml.valueOf("//dynamic-element[@name='Adicional1']/dynamic-content/text()") /> 
35        
36         
37        <#assign valores = entry.getAssetRenderer().getArticle()/> 
38          
39         <#assign groupId = valores["groupId"]/> 
40         
41         <#assign name = valores["urlTitle"]/> 
42          
43         <#assign applyUrlAlter = docXml.valueOf("//dynamic-element[@name='APLIENLACEALTER']/dynamic-content/text()")/> 
44          
45        <#assign assetRenderer = entry.getAssetRenderer() />                  
46         
47        <#assign viewURL = assetPublisherHelper.getAssetViewURL(renderRequest, renderResponse, assetRenderer, entry, !stringUtil.equals(assetLinkBehavior, "showFullContent")) 
48            /> 
49 
50 
51                    <div class="gallery-cell${nameInstancePublisher}"> 
52                                <div class="card-info${nameInstancePublisher}" id="card-info"> 
53                <div class="card-img${nameInstancePublisher}" id="card-img"> 
54                    <img alt="${urlimagen?eval["alt"]}" src="/recursosdb/${urlimagen?eval["groupId"]}/${urlimagen?eval["classPK"]}/${urlimagen?eval["name"]}/${urlimagen?eval["uuid"]}" title="${titulo}"> 
55                    <#if assetRenderer.hasEditPermission(themeDisplay.getPermissionChecker())> 
56                        <#assign editPortletURL = assetRenderer.getURLEdit(renderRequest, renderResponse, windowStateFactory.getWindowState("NORMAL"), themeDisplay.getURLCurrent())!"" /> 
57                        <#if validator.isNotNull(editPortletURL)> 
58                            <a class="editOptionmas" href="${editPortletURL.toString()}">Editar &#x2710</a> 
59                        </#if> 
60                    </#if> 
61                </div>     
62                <div class="card-txt${nameInstancePublisher}" id="card-txt"> 
63                    <div class="card-title${nameInstancePublisher}" id="card-title">${titulo}</div> 
64                    <div class="card-lead${nameInstancePublisher}" id="card-lead">${contenido}</div> 
65                    <div class="card-btn${nameInstancePublisher}" id="card-btn"> 
66                        
67                            <a class="link${nameInstancePublisher}" href="${linkext}" target="_blank"> 
68                                Ver más 
69                            </a> 
70                         
71                    </div> 
72                </div> 
73                 
74            </div> 
75        </div>            
76    </#list> 
77</div> 
78 
79                 
80     
81    
82 
83<!---------------------- ESTLOS BASICOS ------------------------> 
84 
85    <style> 
86 
87        .cards-cont${nameInstancePublisher} { 
88            width: 100%; 
89            display: flex; 
90            justify-content: center; 
91            flex-wrap: wrap; 
92             
93
94         
95         
96        .card-info${nameInstancePublisher} { 
97             
98            width: 250px; 
99            height: 350px; 
100            margin: 15px; 
101            display:flex; 
102            align-content:center; 
103            align-items:center; 
104            flex-wrap:wrap; 
105
106         
107        .card-img${nameInstancePublisher} { 
108            width: 250px; 
109            height: 350px; 
110            border-radius: 10px; 
111            -webkit-box-shadow: 0px 2px 17px 1px rgb(0 0 0 / 23%); 
112            box-shadow: 0px 2px 17px 1px rgb(0 0 0 / 23%); 
113            box-sizing: border-box; 
114            background-position: center; 
115            background-size: cover; 
116            -webkit-transition: all 500ms ease-in-out; // IE 9 
117            -moz-transition: all 500ms ease-in-out; // Firefox 
118            -ms-transition: all 500ms ease-in-out; // Safari and Chrome  
119            -o-transition: all 500ms ease-in-out; // Opera 
120            transition: all 500ms ease-in-out; 
121            position:relative; 
122            display:flex; 
123
124         
125        .card-info${nameInstancePublisher}:hover .card-img${nameInstancePublisher} { 
126            width: 250px; 
127            height: 350px; 
128            border-radius: 10px; 
129            box-sizing: border-box; 
130            background-position: center; 
131            background-size: cover; 
132            -moz-transform: scale(1.02); 
133            -webkit-transform: scale(1.02); 
134            -o-transform: scale(1.02); 
135            -ms-transform: scale(1.02); 
136            transform: scale(1.02); 
137
138         
139        .card-img${nameInstancePublisher} img{ 
140            vertical-align: middle; 
141            border-style: none; 
142            width: 100%; 
143            height: 350px; 
144            object-fit: cover; 
145            object-position: center; 
146            border-radius: 10px; 
147
148         
149        .card-txt${nameInstancePublisher} { 
150            position: absolute; 
151            display:flex; 
152            padding: 20px; 
153            color: #FFF; 
154            opacity: 1; 
155            transition: all 500ms ease-in-out; 
156            width: 90%; 
157            flex-wrap:wrap; 
158            max-width: 250px; 
159
160        #card-txt{ 
161            display:none;  
162            opacity:0; 
163            transition: all 1s; 
164            -webkit-transition: all 1s; 
165
166         
167        #card-info:hover #card-txt{ 
168            display:flex; 
169            opacity:1; 
170            transition: all 1s; 
171            -webkit-transition: all 1s; 
172
173         
174        #card-info:hover #card-img{filter: brightness(0.3);} 
175         
176        .card-title${nameInstancePublisher} { 
177            font-family: HelveticaBold; 
178            font-size: 1rem; 
179            transition: all 500ms ease-in-out; 
180            width:100%; 
181
182         
183        .card-lead${nameInstancePublisher} { 
184            font-family: HelveticaLight; 
185            font-size: 0.9rem; 
186            transition: all 500ms ease-in-out; 
187            width: 100%; 
188
189         
190        .card-btn${nameInstancePublisher} { 
191            padding: 5px; 
192            font-family: HelveticaLight; 
193            border: 1px solid #fff; 
194            width: auto; 
195            font-size: 0.8rem; 
196            margin-top: 10px; 
197            display: flex; 
198            border-radius: 10px; 
199            text-align: center; 
200            /* margin: 0 auto; */ 
201            /* align-content: center; */ 
202            justify-content: center; 
203            cursor: pointer; 
204            opacity: 1; 
205
206         
207        .card-info${nameInstancePublisher}:hover .card-btn${nameInstancePublisher}{ 
208            background-color:#FFF; 
209            color:#494949; 
210            width: auto; 
211            padding: 5px 10px; 
212            border-radius: 5px; 
213
214         
215        .card-btn${nameInstancePublisher} a{ 
216            color:#FFF; 
217            text-decoration:none; 
218
219         
220        .card-info${nameInstancePublisher}:hover .card-btn${nameInstancePublisher} a{ 
221            color:#494949; 
222             
223
224         
225         
226        .editOptionmas{ 
227            position: absolute; 
228            background-color: #173268; 
229            padding: 2px 5px; 
230            color: #FFF; 
231            font-family:HelveticaLight; 
232            display:flex; 
233            flex-wrap:nowrap; 
234            width: 85px; 
235            top:0px; 
236            justify-content: center; 
237            border-radius:10px 0px 10px 0px;    
238
239         
240        .editOptionmas:hover{ 
241            text-decoration:none; 
242            color:#FFF; 
243            font-family:HelveticaBold; 
244
245         
246    </style> 
247 
248    <style> 
249        .gallery${nameInstancePublisher} { 
250             
251            margin: 0 auto; 
252            width: 97%; 
253            max-width:1200px; 
254            margin-bottom:30px; 
255            height:420px; 
256
257         
258        .gallery-cell${nameInstancePublisher} { 
259            width: 22%; 
260            height: auto; 
261            margin-right: 10px; 
262            counter-increment: gallery-cell; 
263
264        /* cell number */ 
265         
266        .gallery-cell${nameInstancePublisher}:before { 
267            display: block; 
268            text-align: center; 
269            /content: counter(gallery-cell);/ 
270            line-height: 200px; 
271            font-size: 80px; 
272            color: white; 
273
274         
275        @media screen and (max-width: 640px) { 
276            .gallery-cell${nameInstancePublisher} { 
277                width: 100%; 
278                height: auto; 
279                margin-right: 10px; 
280                counter-increment: gallery-cell; 
281
282
283 
284 
285        .flickity-page-dots .dot.is-selected { 
286            opacity: 1; 
287            background: #2c5697; 
288
289 
290        .flickity-page-dots .dot { 
291            display: inline-block; 
292            width: 8px!important; 
293            height: 8px!important; 
294            margin: 0 5px!important; 
295            background: #494949; 
296            border-radius: 50%; 
297            opacity: 0.25; 
298            cursor: pointer; 
299
300         
301        .flickity-page-dots { 
302            position: absolute; 
303            width: 100%; 
304            bottom: 0px!important; 
305            padding: 0; 
306            margin: 0; 
307            list-style: none; 
308            text-align: center; 
309            line-height: 1; 
310            margin-bottom: 0px; 
311
312 
313        .flickity-prev-next-button.previous { 
314            left: -50px!important; 
315
316 
317        .flickity-prev-next-button.next { 
318            right: -50px!important; 
319
320 
321        @media screen and (max-width: 640px) { 
322            .flickity-prev-next-button.previous { 
323            left: 10px!important; 
324
325 
326        .flickity-prev-next-button.next { 
327            right: 10px!important; 
328
329         
330        .flickity-prev-next-button { 
331            top: 25%!important; 
332            width: 44px; 
333            height: 44px; 
334            border-radius: 50%; 
335            transform: translateY(-50%); 
336
337
338 
339 
340    </style> 
341 
342<!------------------------------------------------------- ESTILOS DEL SCRIPT ----------------------------------------------> 
343 
344 
345<style> 
346    
347.flickity-enabled { 
348  position: relative; 
349
350 
351.flickity-enabled:focus { outline: none; } 
352 
353.flickity-viewport { 
354  overflow: hidden; 
355  position: relative; 
356  height: 100%; 
357
358 
359.flickity-slider { 
360  position: absolute; 
361  width: 100%; 
362  height: 100%; 
363
364 
365/* draggable */ 
366 
367.flickity-enabled.is-draggable { 
368  -webkit-tap-highlight-color: transparent; 
369  -webkit-user-select: none; 
370     -moz-user-select: none; 
371      -ms-user-select: none; 
372          user-select: none; 
373
374 
375.flickity-enabled.is-draggable .flickity-viewport { 
376  cursor: move; 
377  cursor: -webkit-grab; 
378  cursor: grab; 
379
380 
381.flickity-enabled.is-draggable .flickity-viewport.is-pointer-down { 
382  cursor: -webkit-grabbing; 
383  cursor: grabbing; 
384
385 
386/* ---- flickity-button ---- */ 
387 
388.flickity-button { 
389  position: absolute; 
390  background: hsla(0, 0%, 100%, 0.75); 
391  border: none; 
392  color: #333; 
393
394 
395.flickity-button:hover { 
396  background: white; 
397  cursor: pointer; 
398
399 
400.flickity-button:focus { 
401  outline: none; 
402  box-shadow: 0 0 0 5px #19F; 
403
404 
405.flickity-button:active { 
406  opacity: 0.6; 
407
408 
409.flickity-button:disabled { 
410  opacity: 0.3; 
411  cursor: auto; 
412  /* prevent disabled button from capturing pointer up event. #716 */ 
413  pointer-events: none; 
414
415 
416.flickity-button-icon { 
417  fill: currentColor; 
418
419 
420/* ---- previous/next buttons ---- */ 
421 
422.flickity-prev-next-button { 
423  top: 50%; 
424  width: 44px; 
425  height: 44px; 
426  border-radius: 50%; 
427  /* vertically center */ 
428  transform: translateY(-50%); 
429
430 
431.flickity-prev-next-button.previous { left: 10px; } 
432.flickity-prev-next-button.next { right: 10px; } 
433/* right to left */ 
434.flickity-rtl .flickity-prev-next-button.previous { 
435  left: auto; 
436  right: 10px; 
437
438.flickity-rtl .flickity-prev-next-button.next { 
439  right: auto; 
440  left: 10px; 
441
442 
443.flickity-prev-next-button .flickity-button-icon { 
444  position: absolute; 
445  left: 20%; 
446  top: 20%; 
447  width: 60%; 
448  height: 60%; 
449
450 
451/* ---- page dots ---- */ 
452 
453.flickity-page-dots { 
454  position: absolute; 
455  width: 100%; 
456  bottom: -25px; 
457  padding: 0; 
458  margin: 0; 
459  list-style: none; 
460  text-align: center; 
461  line-height: 1; 
462
463 
464.flickity-rtl .flickity-page-dots { direction: rtl; } 
465 
466.flickity-page-dots .dot { 
467  display: inline-block; 
468  width: 10px; 
469  height: 10px; 
470  margin: 0 8px; 
471  background: #333; 
472  border-radius: 50%; 
473  opacity: 0.25; 
474  cursor: pointer; 
475
476 
477.flickity-page-dots .dot.is-selected { 
478  opacity: 1; 
479
480    </style> 
481 
482 
483<!-------------------------------------------------------------  SCRIPT PRINCIPAL --------------------------------------------------------------------------> 
484 
485<script> 
486    /*! 
487 * Flickity PACKAGED v2.2.2 
488 * Touch, responsive, flickable carousels 
489
490 * Licensed GPLv3 for open source use 
491 * or Flickity Commercial License for commercial use 
492
493 * https://flickity.metafizzy.co 
494 * Copyright 2015-2021 Metafizzy 
495 */ 
496 
497/** 
498 * Bridget makes jQuery widgets 
499 * v2.0.1 
500 * MIT license 
501 */ 
502 
503/* jshint browser: true, strict: true, undef: true, unused: true */ 
504 
505( function( window, factory ) { 
506  // universal module definition 
507  /*jshint strict: false */ /* globals define, module, require */ 
508  if ( typeof define == 'function' && define.amd ) { 
509    // AMD 
510    define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) { 
511      return factory( window, jQuery ); 
512    }); 
513  } else if ( typeof module == 'object' && module.exports ) { 
514    // CommonJS 
515    module.exports = factory( 
516      window, 
517      require('jquery') 
518    ); 
519  } else { 
520    // browser global 
521    window.jQueryBridget = factory( 
522      window, 
523      window.jQuery 
524    ); 
525
526 
527}( window, function factory( window, jQuery ) { 
528'use strict'; 
529 
530// ----- utils ----- // 
531 
532var arraySlice = Array.prototype.slice; 
533 
534// helper function for logging errors 
535// $.error breaks jQuery chaining 
536var console = window.console; 
537var logError = typeof console == 'undefined' ? function() {} : 
538  function( message ) { 
539    console.error( message ); 
540  }; 
541 
542// ----- jQueryBridget ----- // 
543 
544function jQueryBridget( namespace, PluginClass, $ ) { 
545  $ = $ || jQuery || window.jQuery; 
546  if ( !$ ) { 
547    return; 
548
549 
550  // add option method -> $().plugin('option', {...}) 
551  if ( !PluginClass.prototype.option ) { 
552    // option setter 
553    PluginClass.prototype.option = function( opts ) { 
554      // bail out if not an object 
555      if ( !$.isPlainObject( opts ) ){ 
556        return; 
557
558      this.options = $.extend( true, this.options, opts ); 
559    }; 
560
561 
562  // make jQuery plugin 
563  $.fn[ namespace ] = function( arg0 /*, arg1 */ ) { 
564    if ( typeof arg0 == 'string' ) { 
565      // method call $().plugin( 'methodName', { options } ) 
566      // shift arguments by 1 
567      var args = arraySlice.call( arguments, 1 ); 
568      return methodCall( this, arg0, args ); 
569
570    // just $().plugin({ options }) 
571    plainCall( this, arg0 ); 
572    return this; 
573  }; 
574 
575  // $().plugin('methodName') 
576  function methodCall( $elems, methodName, args ) { 
577    var returnValue; 
578    var pluginMethodStr = '$().' + namespace + '("' + methodName + '")'; 
579 
580    $elems.each( function( i, elem ) { 
581      // get instance 
582      var instance = $.data( elem, namespace ); 
583      if ( !instance ) { 
584        logError( namespace + ' not initialized. Cannot call methods, i.e. ' + 
585          pluginMethodStr ); 
586        return; 
587
588 
589      var method = instance[ methodName ]; 
590      if ( !method || methodName.charAt(0) == '_' ) { 
591        logError( pluginMethodStr + ' is not a valid method' ); 
592        return; 
593
594 
595      // apply method, get return value 
596      var value = method.apply( instance, args ); 
597      // set return value if value is returned, use only first value 
598      returnValue = returnValue === undefined ? value : returnValue; 
599    }); 
600 
601    return returnValue !== undefined ? returnValue : $elems; 
602
603 
604  function plainCall( $elems, options ) { 
605    $elems.each( function( i, elem ) { 
606      var instance = $.data( elem, namespace ); 
607      if ( instance ) { 
608        // set options & init 
609        instance.option( options ); 
610        instance._init(); 
611      } else { 
612        // initialize new instance 
613        instance = new PluginClass( elem, options ); 
614        $.data( elem, namespace, instance ); 
615
616    }); 
617
618 
619  updateJQuery( $ ); 
620 
621
622 
623// ----- updateJQuery ----- // 
624 
625// set $.bridget for v1 backwards compatibility 
626function updateJQuery( $ ) { 
627  if ( !$ || ( $ && $.bridget ) ) { 
628    return; 
629
630  $.bridget = jQueryBridget; 
631
632 
633updateJQuery( jQuery || window.jQuery ); 
634 
635// -----  ----- // 
636 
637return jQueryBridget; 
638 
639})); 
640 
641/** 
642 * EvEmitter v1.1.0 
643 * Lil' event emitter 
644 * MIT License 
645 */ 
646 
647/* jshint unused: true, undef: true, strict: true */ 
648 
649( function( global, factory ) { 
650  // universal module definition 
651  /* jshint strict: false */ /* globals define, module, window */ 
652  if ( typeof define == 'function' && define.amd ) { 
653    // AMD - RequireJS 
654    define( 'ev-emitter/ev-emitter',factory ); 
655  } else if ( typeof module == 'object' && module.exports ) { 
656    // CommonJS - Browserify, Webpack 
657    module.exports = factory(); 
658  } else { 
659    // Browser globals 
660    global.EvEmitter = factory(); 
661
662 
663}( typeof window != 'undefined' ? window : this, function() { 
664 
665 
666 
667function EvEmitter() {} 
668 
669var proto = EvEmitter.prototype; 
670 
671proto.on = function( eventName, listener ) { 
672  if ( !eventName || !listener ) { 
673    return; 
674
675  // set events hash 
676  var events = this._events = this._events || {}; 
677  // set listeners array 
678  var listeners = events[ eventName ] = events[ eventName ] || []; 
679  // only add once 
680  if ( listeners.indexOf( listener ) == -1 ) { 
681    listeners.push( listener ); 
682
683 
684  return this; 
685}; 
686 
687proto.once = function( eventName, listener ) { 
688  if ( !eventName || !listener ) { 
689    return; 
690
691  // add event 
692  this.on( eventName, listener ); 
693  // set once flag 
694  // set onceEvents hash 
695  var onceEvents = this._onceEvents = this._onceEvents || {}; 
696  // set onceListeners object 
697  var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; 
698  // set flag 
699  onceListeners[ listener ] = true; 
700 
701  return this; 
702}; 
703 
704proto.off = function( eventName, listener ) { 
705  var listeners = this._events && this._events[ eventName ]; 
706  if ( !listeners || !listeners.length ) { 
707    return; 
708
709  var index = listeners.indexOf( listener ); 
710  if ( index != -1 ) { 
711    listeners.splice( index, 1 ); 
712
713 
714  return this; 
715}; 
716 
717proto.emitEvent = function( eventName, args ) { 
718  var listeners = this._events && this._events[ eventName ]; 
719  if ( !listeners || !listeners.length ) { 
720    return; 
721
722  // copy over to avoid interference if .off() in listener 
723  listeners = listeners.slice(0); 
724  args = args || []; 
725  // once stuff 
726  var onceListeners = this._onceEvents && this._onceEvents[ eventName ]; 
727 
728  for ( var i=0; i < listeners.length; i++ ) { 
729    var listener = listeners[i] 
730    var isOnce = onceListeners && onceListeners[ listener ]; 
731    if ( isOnce ) { 
732      // remove listener 
733      // remove before trigger to prevent recursion 
734      this.off( eventName, listener ); 
735      // unset once flag 
736      delete onceListeners[ listener ]; 
737
738    // trigger listener 
739    listener.apply( this, args ); 
740
741 
742  return this; 
743}; 
744 
745proto.allOff = function() { 
746  delete this._events; 
747  delete this._onceEvents; 
748}; 
749 
750return EvEmitter; 
751 
752})); 
753 
754/*! 
755 * getSize v2.0.3 
756 * measure size of elements 
757 * MIT license 
758 */ 
759 
760/* jshint browser: true, strict: true, undef: true, unused: true */ 
761/* globals console: false */ 
762 
763( function( window, factory ) { 
764  /* jshint strict: false */ /* globals define, module */ 
765  if ( typeof define == 'function' && define.amd ) { 
766    // AMD 
767    define( 'get-size/get-size',factory ); 
768  } else if ( typeof module == 'object' && module.exports ) { 
769    // CommonJS 
770    module.exports = factory(); 
771  } else { 
772    // browser global 
773    window.getSize = factory(); 
774
775 
776})( window, function factory() { 
777'use strict'; 
778 
779// -------------------------- helpers -------------------------- // 
780 
781// get a number from a string, not a percentage 
782function getStyleSize( value ) { 
783  var num = parseFloat( value ); 
784  // not a percent like '100%', and a number 
785  var isValid = value.indexOf('%') == -1 && !isNaN( num ); 
786  return isValid && num; 
787
788 
789function noop() {} 
790 
791var logError = typeof console == 'undefined' ? noop : 
792  function( message ) { 
793    console.error( message ); 
794  }; 
795 
796// -------------------------- measurements -------------------------- // 
797 
798var measurements = [ 
799  'paddingLeft', 
800  'paddingRight', 
801  'paddingTop', 
802  'paddingBottom', 
803  'marginLeft', 
804  'marginRight', 
805  'marginTop', 
806  'marginBottom', 
807  'borderLeftWidth', 
808  'borderRightWidth', 
809  'borderTopWidth', 
810  'borderBottomWidth' 
811]; 
812 
813var measurementsLength = measurements.length; 
814 
815function getZeroSize() { 
816  var size = { 
817    width: 0, 
818    height: 0, 
819    innerWidth: 0, 
820    innerHeight: 0, 
821    outerWidth: 0, 
822    outerHeight: 0 
823  }; 
824  for ( var i=0; i < measurementsLength; i++ ) { 
825    var measurement = measurements[i]; 
826    size[ measurement ] = 0; 
827
828  return size; 
829
830 
831// -------------------------- getStyle -------------------------- // 
832 
833/** 
834 * getStyle, get style of element, check for Firefox bug 
835 * https://bugzilla.mozilla.org/show_bug.cgi?id=548397 
836 */ 
837function getStyle( elem ) { 
838  var style = getComputedStyle( elem ); 
839  if ( !style ) { 
840    logError( 'Style returned ' + style + 
841      '. Are you running this code in a hidden iframe on Firefox? ' + 
842      'See https://bit.ly/getsizebug1' ); 
843
844  return style; 
845
846 
847// -------------------------- setup -------------------------- // 
848 
849var isSetup = false; 
850 
851var isBoxSizeOuter; 
852 
853/** 
854 * setup 
855 * check isBoxSizerOuter 
856 * do on first getSize() rather than on page load for Firefox bug 
857 */ 
858function setup() { 
859  // setup once 
860  if ( isSetup ) { 
861    return; 
862
863  isSetup = true; 
864 
865  // -------------------------- box sizing -------------------------- // 
866 
867  /** 
868   * Chrome & Safari measure the outer-width on style.width on border-box elems 
869   * IE11 & Firefox<29 measures the inner-width 
870   */ 
871  var div = document.createElement('div'); 
872  div.style.width = '200px'; 
873  div.style.padding = '1px 2px 3px 4px'; 
874  div.style.borderStyle = 'solid'; 
875  div.style.borderWidth = '1px 2px 3px 4px'; 
876  div.style.boxSizing = 'border-box'; 
877 
878  var body = document.body || document.documentElement; 
879  body.appendChild( div ); 
880  var style = getStyle( div ); 
881  // round value for browser zoom. desandro/masonry#928 
882  isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200; 
883  getSize.isBoxSizeOuter = isBoxSizeOuter; 
884 
885  body.removeChild( div ); 
886
887 
888// -------------------------- getSize -------------------------- // 
889 
890function getSize( elem ) { 
891  setup(); 
892 
893  // use querySeletor if elem is string 
894  if ( typeof elem == 'string' ) { 
895    elem = document.querySelector( elem ); 
896
897 
898  // do not proceed on non-objects 
899  if ( !elem || typeof elem != 'object' || !elem.nodeType ) { 
900    return; 
901
902 
903  var style = getStyle( elem ); 
904 
905  // if hidden, everything is 0 
906  if ( style.display == 'none' ) { 
907    return getZeroSize(); 
908
909 
910  var size = {}; 
911  size.width = elem.offsetWidth; 
912  size.height = elem.offsetHeight; 
913 
914  var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box'; 
915 
916  // get all measurements 
917  for ( var i=0; i < measurementsLength; i++ ) { 
918    var measurement = measurements[i]; 
919    var value = style[ measurement ]; 
920    var num = parseFloat( value ); 
921    // any 'auto', 'medium' value will be 0 
922    size[ measurement ] = !isNaN( num ) ? num : 0; 
923
924 
925  var paddingWidth = size.paddingLeft + size.paddingRight; 
926  var paddingHeight = size.paddingTop + size.paddingBottom; 
927  var marginWidth = size.marginLeft + size.marginRight; 
928  var marginHeight = size.marginTop + size.marginBottom; 
929  var borderWidth = size.borderLeftWidth + size.borderRightWidth; 
930  var borderHeight = size.borderTopWidth + size.borderBottomWidth; 
931 
932  var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter; 
933 
934  // overwrite width and height if we can get it from style 
935  var styleWidth = getStyleSize( style.width ); 
936  if ( styleWidth !== false ) { 
937    size.width = styleWidth + 
938      // add padding and border unless it's already including it 
939      ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth ); 
940
941 
942  var styleHeight = getStyleSize( style.height ); 
943  if ( styleHeight !== false ) { 
944    size.height = styleHeight + 
945      // add padding and border unless it's already including it 
946      ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight ); 
947
948 
949  size.innerWidth = size.width - ( paddingWidth + borderWidth ); 
950  size.innerHeight = size.height - ( paddingHeight + borderHeight ); 
951 
952  size.outerWidth = size.width + marginWidth; 
953  size.outerHeight = size.height + marginHeight; 
954 
955  return size; 
956
957 
958return getSize; 
959 
960}); 
961 
962/** 
963 * matchesSelector v2.0.2 
964 * matchesSelector( element, '.selector' ) 
965 * MIT license 
966 */ 
967 
968/*jshint browser: true, strict: true, undef: true, unused: true */ 
969 
970( function( window, factory ) { 
971  /*global define: false, module: false */ 
972  'use strict'; 
973  // universal module definition 
974  if ( typeof define == 'function' && define.amd ) { 
975    // AMD 
976    define( 'desandro-matches-selector/matches-selector',factory ); 
977  } else if ( typeof module == 'object' && module.exports ) { 
978    // CommonJS 
979    module.exports = factory(); 
980  } else { 
981    // browser global 
982    window.matchesSelector = factory(); 
983
984 
985}( window, function factory() { 
986  'use strict'; 
987 
988  var matchesMethod = ( function() { 
989    var ElemProto = window.Element.prototype; 
990    // check for the standard method name first 
991    if ( ElemProto.matches ) { 
992      return 'matches'; 
993
994    // check un-prefixed 
995    if ( ElemProto.matchesSelector ) { 
996      return 'matchesSelector'; 
997
998    // check vendor prefixes 
999    var prefixes = [ 'webkit', 'moz', 'ms', 'o' ]; 
1000 
1001    for ( var i=0; i < prefixes.length; i++ ) { 
1002      var prefix = prefixes[i]; 
1003      var method = prefix + 'MatchesSelector'; 
1004      if ( ElemProto[ method ] ) { 
1005        return method; 
1006
1007
1008  })(); 
1009 
1010  return function matchesSelector( elem, selector ) { 
1011    return elem[ matchesMethod ]( selector ); 
1012  }; 
1013 
1014})); 
1015 
1016/** 
1017 * Fizzy UI utils v2.0.7 
1018 * MIT license 
1019 */ 
1020 
1021/*jshint browser: true, undef: true, unused: true, strict: true */ 
1022 
1023( function( window, factory ) { 
1024  // universal module definition 
1025  /*jshint strict: false */ /*globals define, module, require */ 
1026 
1027  if ( typeof define == 'function' && define.amd ) { 
1028    // AMD 
1029    define( 'fizzy-ui-utils/utils',[ 
1030      'desandro-matches-selector/matches-selector' 
1031    ], function( matchesSelector ) { 
1032      return factory( window, matchesSelector ); 
1033    }); 
1034  } else if ( typeof module == 'object' && module.exports ) { 
1035    // CommonJS 
1036    module.exports = factory( 
1037      window, 
1038      require('desandro-matches-selector') 
1039    ); 
1040  } else { 
1041    // browser global 
1042    window.fizzyUIUtils = factory( 
1043      window, 
1044      window.matchesSelector 
1045    ); 
1046
1047 
1048}( window, function factory( window, matchesSelector ) { 
1049 
1050 
1051 
1052var utils = {}; 
1053 
1054// ----- extend ----- // 
1055 
1056// extends objects 
1057utils.extend = function( a, b ) { 
1058  for ( var prop in b ) { 
1059    a[ prop ] = b[ prop ]; 
1060
1061  return a; 
1062}; 
1063 
1064// ----- modulo ----- // 
1065 
1066utils.modulo = function( num, div ) { 
1067  return ( ( num % div ) + div ) % div; 
1068}; 
1069 
1070// ----- makeArray ----- // 
1071 
1072var arraySlice = Array.prototype.slice; 
1073 
1074// turn element or nodeList into an array 
1075utils.makeArray = function( obj ) { 
1076  if ( Array.isArray( obj ) ) { 
1077    // use object if already an array 
1078    return obj; 
1079
1080  // return empty array if undefined or null. #6 
1081  if ( obj === null || obj === undefined ) { 
1082    return []; 
1083
1084 
1085  var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; 
1086  if ( isArrayLike ) { 
1087    // convert nodeList to array 
1088    return arraySlice.call( obj ); 
1089
1090 
1091  // array of single index 
1092  return [ obj ]; 
1093}; 
1094 
1095// ----- removeFrom ----- // 
1096 
1097utils.removeFrom = function( ary, obj ) { 
1098  var index = ary.indexOf( obj ); 
1099  if ( index != -1 ) { 
1100    ary.splice( index, 1 ); 
1101
1102}; 
1103 
1104// ----- getParent ----- // 
1105 
1106utils.getParent = function( elem, selector ) { 
1107  while ( elem.parentNode && elem != document.body ) { 
1108    elem = elem.parentNode; 
1109    if ( matchesSelector( elem, selector ) ) { 
1110      return elem; 
1111
1112
1113}; 
1114 
1115// ----- getQueryElement ----- // 
1116 
1117// use element as selector string 
1118utils.getQueryElement = function( elem ) { 
1119  if ( typeof elem == 'string' ) { 
1120    return document.querySelector( elem ); 
1121
1122  return elem; 
1123}; 
1124 
1125// ----- handleEvent ----- // 
1126 
1127// enable .ontype to trigger from .addEventListener( elem, 'type' ) 
1128utils.handleEvent = function( event ) { 
1129  var method = 'on' + event.type; 
1130  if ( this[ method ] ) { 
1131    this[ method ]( event ); 
1132
1133}; 
1134 
1135// ----- filterFindElements ----- // 
1136 
1137utils.filterFindElements = function( elems, selector ) { 
1138  // make array of elems 
1139  elems = utils.makeArray( elems ); 
1140  var ffElems = []; 
1141 
1142  elems.forEach( function( elem ) { 
1143    // check that elem is an actual element 
1144    if ( !( elem instanceof HTMLElement ) ) { 
1145      return; 
1146
1147    // add elem if no selector 
1148    if ( !selector ) { 
1149      ffElems.push( elem ); 
1150      return; 
1151
1152    // filter & find items if we have a selector 
1153    // filter 
1154    if ( matchesSelector( elem, selector ) ) { 
1155      ffElems.push( elem ); 
1156
1157    // find children 
1158    var childElems = elem.querySelectorAll( selector ); 
1159    // concat childElems to filterFound array 
1160    for ( var i=0; i < childElems.length; i++ ) { 
1161      ffElems.push( childElems[i] ); 
1162
1163  }); 
1164 
1165  return ffElems; 
1166}; 
1167 
1168// ----- debounceMethod ----- // 
1169 
1170utils.debounceMethod = function( _class, methodName, threshold ) { 
1171  threshold = threshold || 100; 
1172  // original method 
1173  var method = _class.prototype[ methodName ]; 
1174  var timeoutName = methodName + 'Timeout'; 
1175 
1176  _class.prototype[ methodName ] = function() { 
1177    var timeout = this[ timeoutName ]; 
1178    clearTimeout( timeout ); 
1179 
1180    var args = arguments; 
1181    var _this = this; 
1182    this[ timeoutName ] = setTimeout( function() { 
1183      method.apply( _this, args ); 
1184      delete _this[ timeoutName ]; 
1185    }, threshold ); 
1186  }; 
1187}; 
1188 
1189// ----- docReady ----- // 
1190 
1191utils.docReady = function( callback ) { 
1192  var readyState = document.readyState; 
1193  if ( readyState == 'complete' || readyState == 'interactive' ) { 
1194    // do async to allow for other scripts to run. metafizzy/flickity#441 
1195    setTimeout( callback ); 
1196  } else { 
1197    document.addEventListener( 'DOMContentLoaded', callback ); 
1198
1199}; 
1200 
1201// ----- htmlInit ----- // 
1202 
1203// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ 
1204utils.toDashed = function( str ) { 
1205  return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) { 
1206    return $1 + '-' + $2; 
1207  }).toLowerCase(); 
1208}; 
1209 
1210var console = window.console; 
1211/** 
1212 * allow user to initialize classes via [data-namespace] or .js-namespace class 
1213 * htmlInit( Widget, 'widgetName' ) 
1214 * options are parsed from data-namespace-options 
1215 */ 
1216utils.htmlInit = function( WidgetClass, namespace ) { 
1217  utils.docReady( function() { 
1218    var dashedNamespace = utils.toDashed( namespace ); 
1219    var dataAttr = 'data-' + dashedNamespace; 
1220    var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' ); 
1221    var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace ); 
1222    var elems = utils.makeArray( dataAttrElems ) 
1223      .concat( utils.makeArray( jsDashElems ) ); 
1224    var dataOptionsAttr = dataAttr + '-options'; 
1225    var jQuery = window.jQuery; 
1226 
1227    elems.forEach( function( elem ) { 
1228      var attr = elem.getAttribute( dataAttr ) || 
1229        elem.getAttribute( dataOptionsAttr ); 
1230      var options; 
1231      try { 
1232        options = attr && JSON.parse( attr ); 
1233      } catch ( error ) { 
1234        // log error, do not initialize 
1235        if ( console ) { 
1236          console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className + 
1237          ': ' + error ); 
1238
1239        return; 
1240
1241      // initialize 
1242      var instance = new WidgetClass( elem, options ); 
1243      // make available via $().data('namespace') 
1244      if ( jQuery ) { 
1245        jQuery.data( elem, namespace, instance ); 
1246
1247    }); 
1248 
1249  }); 
1250}; 
1251 
1252// -----  ----- // 
1253 
1254return utils; 
1255 
1256})); 
1257 
1258// Flickity.Cell 
1259( function( window, factory ) { 
1260  // universal module definition 
1261  if ( typeof define == 'function' && define.amd ) { 
1262    // AMD 
1263    define( 'flickity/js/cell',[ 
1264      'get-size/get-size', 
1265    ], function( getSize ) { 
1266      return factory( window, getSize ); 
1267    } ); 
1268  } else if ( typeof module == 'object' && module.exports ) { 
1269    // CommonJS 
1270    module.exports = factory( 
1271        window, 
1272        require('get-size') 
1273    ); 
1274  } else { 
1275    // browser global 
1276    window.Flickity = window.Flickity || {}; 
1277    window.Flickity.Cell = factory( 
1278        window, 
1279        window.getSize 
1280    ); 
1281
1282 
1283}( window, function factory( window, getSize ) { 
1284 
1285 
1286 
1287function Cell( elem, parent ) { 
1288  this.element = elem; 
1289  this.parent = parent; 
1290 
1291  this.create(); 
1292
1293 
1294var proto = Cell.prototype; 
1295 
1296proto.create = function() { 
1297  this.element.style.position = 'absolute'; 
1298  this.element.setAttribute( 'aria-hidden', 'true' ); 
1299  this.x = 0; 
1300  this.shift = 0; 
1301}; 
1302 
1303proto.destroy = function() { 
1304  // reset style 
1305  this.unselect(); 
1306  this.element.style.position = ''; 
1307  var side = this.parent.originSide; 
1308  this.element.style[ side ] = ''; 
1309  this.element.removeAttribute('aria-hidden'); 
1310}; 
1311 
1312proto.getSize = function() { 
1313  this.size = getSize( this.element ); 
1314}; 
1315 
1316proto.setPosition = function( x ) { 
1317  this.x = x; 
1318  this.updateTarget(); 
1319  this.renderPosition( x ); 
1320}; 
1321 
1322// setDefaultTarget v1 method, backwards compatibility, remove in v3 
1323proto.updateTarget = proto.setDefaultTarget = function() { 
1324  var marginProperty = this.parent.originSide == 'left' ? 'marginLeft' : 'marginRight'; 
1325  this.target = this.x + this.size[ marginProperty ] + 
1326    this.size.width * this.parent.cellAlign; 
1327}; 
1328 
1329proto.renderPosition = function( x ) { 
1330  // render position of cell with in slider 
1331  var side = this.parent.originSide; 
1332  this.element.style[ side ] = this.parent.getPositionValue( x ); 
1333}; 
1334 
1335proto.select = function() { 
1336  this.element.classList.add('is-selected'); 
1337  this.element.removeAttribute('aria-hidden'); 
1338}; 
1339 
1340proto.unselect = function() { 
1341  this.element.classList.remove('is-selected'); 
1342  this.element.setAttribute( 'aria-hidden', 'true' ); 
1343}; 
1344 
1345/** 
1346 * @param {Integer} shift - 0, 1, or -1 
1347 */ 
1348proto.wrapShift = function( shift ) { 
1349  this.shift = shift; 
1350  this.renderPosition( this.x + this.parent.slideableWidth * shift ); 
1351}; 
1352 
1353proto.remove = function() { 
1354  this.element.parentNode.removeChild( this.element ); 
1355}; 
1356 
1357return Cell; 
1358 
1359} ) ); 
1360 
1361// slide 
1362( function( window, factory ) { 
1363  // universal module definition 
1364  if ( typeof define == 'function' && define.amd ) { 
1365    // AMD 
1366    define( 'flickity/js/slide',factory ); 
1367  } else if ( typeof module == 'object' && module.exports ) { 
1368    // CommonJS 
1369    module.exports = factory(); 
1370  } else { 
1371    // browser global 
1372    window.Flickity = window.Flickity || {}; 
1373    window.Flickity.Slide = factory(); 
1374
1375 
1376}( window, function factory() { 
1377'use strict'; 
1378 
1379function Slide( parent ) { 
1380  this.parent = parent; 
1381  this.isOriginLeft = parent.originSide == 'left'; 
1382  this.cells = []; 
1383  this.outerWidth = 0; 
1384  this.height = 0; 
1385
1386 
1387var proto = Slide.prototype; 
1388 
1389proto.addCell = function( cell ) { 
1390  this.cells.push( cell ); 
1391  this.outerWidth += cell.size.outerWidth; 
1392  this.height = Math.max( cell.size.outerHeight, this.height ); 
1393  // first cell stuff 
1394  if ( this.cells.length == 1 ) { 
1395    this.x = cell.x; // x comes from first cell 
1396    var beginMargin = this.isOriginLeft ? 'marginLeft' : 'marginRight'; 
1397    this.firstMargin = cell.size[ beginMargin ]; 
1398
1399}; 
1400 
1401proto.updateTarget = function() { 
1402  var endMargin = this.isOriginLeft ? 'marginRight' : 'marginLeft'; 
1403  var lastCell = this.getLastCell(); 
1404  var lastMargin = lastCell ? lastCell.size[ endMargin ] : 0; 
1405  var slideWidth = this.outerWidth - ( this.firstMargin + lastMargin ); 
1406  this.target = this.x + this.firstMargin + slideWidth * this.parent.cellAlign; 
1407}; 
1408 
1409proto.getLastCell = function() { 
1410  return this.cells[ this.cells.length - 1 ]; 
1411}; 
1412 
1413proto.select = function() { 
1414  this.cells.forEach( function( cell ) { 
1415    cell.select(); 
1416  } ); 
1417}; 
1418 
1419proto.unselect = function() { 
1420  this.cells.forEach( function( cell ) { 
1421    cell.unselect(); 
1422  } ); 
1423}; 
1424 
1425proto.getCellElements = function() { 
1426  return this.cells.map( function( cell ) { 
1427    return cell.element; 
1428  } ); 
1429}; 
1430 
1431return Slide; 
1432 
1433} ) ); 
1434 
1435// animate 
1436( function( window, factory ) { 
1437  // universal module definition 
1438  if ( typeof define == 'function' && define.amd ) { 
1439    // AMD 
1440    define( 'flickity/js/animate',[ 
1441      'fizzy-ui-utils/utils', 
1442    ], function( utils ) { 
1443      return factory( window, utils ); 
1444    } ); 
1445  } else if ( typeof module == 'object' && module.exports ) { 
1446    // CommonJS 
1447    module.exports = factory( 
1448        window, 
1449        require('fizzy-ui-utils') 
1450    ); 
1451  } else { 
1452    // browser global 
1453    window.Flickity = window.Flickity || {}; 
1454    window.Flickity.animatePrototype = factory( 
1455        window, 
1456        window.fizzyUIUtils 
1457    ); 
1458
1459 
1460}( window, function factory( window, utils ) { 
1461 
1462 
1463 
1464// -------------------------- animate -------------------------- // 
1465 
1466var proto = {}; 
1467 
1468proto.startAnimation = function() { 
1469  if ( this.isAnimating ) { 
1470    return; 
1471
1472 
1473  this.isAnimating = true; 
1474  this.restingFrames = 0; 
1475  this.animate(); 
1476}; 
1477 
1478proto.animate = function() { 
1479  this.applyDragForce(); 
1480  this.applySelectedAttraction(); 
1481 
1482  var previousX = this.x; 
1483 
1484  this.integratePhysics(); 
1485  this.positionSlider(); 
1486  this.settle( previousX ); 
1487  // animate next frame 
1488  if ( this.isAnimating ) { 
1489    var _this = this; 
1490    requestAnimationFrame( function animateFrame() { 
1491      _this.animate(); 
1492    } ); 
1493
1494}; 
1495 
1496proto.positionSlider = function() { 
1497  var x = this.x; 
1498  // wrap position around 
1499  if ( this.options.wrapAround && this.cells.length > 1 ) { 
1500    x = utils.modulo( x, this.slideableWidth ); 
1501    x -= this.slideableWidth; 
1502    this.shiftWrapCells( x ); 
1503
1504 
1505  this.setTranslateX( x, this.isAnimating ); 
1506  this.dispatchScrollEvent(); 
1507}; 
1508 
1509proto.setTranslateX = function( x, is3d ) { 
1510  x += this.cursorPosition; 
1511  // reverse if right-to-left and using transform 
1512  x = this.options.rightToLeft ? -x : x; 
1513  var translateX = this.getPositionValue( x ); 
1514  // use 3D transforms for hardware acceleration on iOS 
1515  // but use 2D when settled, for better font-rendering 
1516  this.slider.style.transform = is3d ? 
1517    'translate3d(' + translateX + ',0,0)' : 'translateX(' + translateX + ')'; 
1518}; 
1519 
1520proto.dispatchScrollEvent = function() { 
1521  var firstSlide = this.slides[0]; 
1522  if ( !firstSlide ) { 
1523    return; 
1524
1525  var positionX = -this.x - firstSlide.target; 
1526  var progress = positionX / this.slidesWidth; 
1527  this.dispatchEvent( 'scroll', null, [ progress, positionX ] ); 
1528}; 
1529 
1530proto.positionSliderAtSelected = function() { 
1531  if ( !this.cells.length ) { 
1532    return; 
1533
1534  this.x = -this.selectedSlide.target; 
1535  this.velocity = 0; // stop wobble 
1536  this.positionSlider(); 
1537}; 
1538 
1539proto.getPositionValue = function( position ) { 
1540  if ( this.options.percentPosition ) { 
1541    // percent position, round to 2 digits, like 12.34% 
1542    return ( Math.round( ( position / this.size.innerWidth ) * 10000 ) * 0.01 ) + '%'; 
1543  } else { 
1544    // pixel positioning 
1545    return Math.round( position ) + 'px'; 
1546
1547}; 
1548 
1549proto.settle = function( previousX ) { 
1550  // keep track of frames where x hasn't moved 
1551  var isResting = !this.isPointerDown && 
1552      Math.round( this.x * 100 ) == Math.round( previousX * 100 ); 
1553  if ( isResting ) { 
1554    this.restingFrames++; 
1555
1556  // stop animating if resting for 3 or more frames 
1557  if ( this.restingFrames > 2 ) { 
1558    this.isAnimating = false; 
1559    delete this.isFreeScrolling; 
1560    // render position with translateX when settled 
1561    this.positionSlider(); 
1562    this.dispatchEvent( 'settle', null, [ this.selectedIndex ] ); 
1563
1564}; 
1565 
1566proto.shiftWrapCells = function( x ) { 
1567  // shift before cells 
1568  var beforeGap = this.cursorPosition + x; 
1569  this._shiftCells( this.beforeShiftCells, beforeGap, -1 ); 
1570  // shift after cells 
1571  var afterGap = this.size.innerWidth - ( x + this.slideableWidth + this.cursorPosition ); 
1572  this._shiftCells( this.afterShiftCells, afterGap, 1 ); 
1573}; 
1574 
1575proto._shiftCells = function( cells, gap, shift ) { 
1576  for ( var i = 0; i < cells.length; i++ ) { 
1577    var cell = cells[i]; 
1578    var cellShift = gap > 0 ? shift : 0; 
1579    cell.wrapShift( cellShift ); 
1580    gap -= cell.size.outerWidth; 
1581
1582}; 
1583 
1584proto._unshiftCells = function( cells ) { 
1585  if ( !cells || !cells.length ) { 
1586    return; 
1587
1588  for ( var i = 0; i < cells.length; i++ ) { 
1589    cells[i].wrapShift( 0 ); 
1590
1591}; 
1592 
1593// -------------------------- physics -------------------------- // 
1594 
1595proto.integratePhysics = function() { 
1596  this.x += this.velocity; 
1597  this.velocity *= this.getFrictionFactor(); 
1598}; 
1599 
1600proto.applyForce = function( force ) { 
1601  this.velocity += force; 
1602}; 
1603 
1604proto.getFrictionFactor = function() { 
1605  return 1 - this.options[ this.isFreeScrolling ? 'freeScrollFriction' : 'friction' ]; 
1606}; 
1607 
1608proto.getRestingPosition = function() { 
1609  // my thanks to Steven Wittens, who simplified this math greatly 
1610  return this.x + this.velocity / ( 1 - this.getFrictionFactor() ); 
1611}; 
1612 
1613proto.applyDragForce = function() { 
1614  if ( !this.isDraggable || !this.isPointerDown ) { 
1615    return; 
1616
1617  // change the position to drag position by applying force 
1618  var dragVelocity = this.dragX - this.x; 
1619  var dragForce = dragVelocity - this.velocity; 
1620  this.applyForce( dragForce ); 
1621}; 
1622 
1623proto.applySelectedAttraction = function() { 
1624  // do not attract if pointer down or no slides 
1625  var dragDown = this.isDraggable && this.isPointerDown; 
1626  if ( dragDown || this.isFreeScrolling || !this.slides.length ) { 
1627    return; 
1628
1629  var distance = this.selectedSlide.target * -1 - this.x; 
1630  var force = distance * this.options.selectedAttraction; 
1631  this.applyForce( force ); 
1632}; 
1633 
1634return proto; 
1635 
1636} ) ); 
1637 
1638// Flickity main 
1639/* eslint-disable max-params */ 
1640( function( window, factory ) { 
1641  // universal module definition 
1642  if ( typeof define == 'function' && define.amd ) { 
1643    // AMD 
1644    define( 'flickity/js/flickity',[ 
1645      'ev-emitter/ev-emitter', 
1646      'get-size/get-size', 
1647      'fizzy-ui-utils/utils', 
1648      './cell', 
1649      './slide', 
1650      './animate', 
1651    ], function( EvEmitter, getSize, utils, Cell, Slide, animatePrototype ) { 
1652      return factory( window, EvEmitter, getSize, utils, Cell, Slide, animatePrototype ); 
1653    } ); 
1654  } else if ( typeof module == 'object' && module.exports ) { 
1655    // CommonJS 
1656    module.exports = factory( 
1657        window, 
1658        require('ev-emitter'), 
1659        require('get-size'), 
1660        require('fizzy-ui-utils'), 
1661        require('./cell'), 
1662        require('./slide'), 
1663        require('./animate') 
1664    ); 
1665  } else { 
1666    // browser global 
1667    var _Flickity = window.Flickity; 
1668 
1669    window.Flickity = factory( 
1670        window, 
1671        window.EvEmitter, 
1672        window.getSize, 
1673        window.fizzyUIUtils, 
1674        _Flickity.Cell, 
1675        _Flickity.Slide, 
1676        _Flickity.animatePrototype 
1677    ); 
1678
1679 
1680}( window, function factory( window, EvEmitter, getSize, 
1681    utils, Cell, Slide, animatePrototype ) { 
1682 
1683/* eslint-enable max-params */ 
1684 
1685 
1686// vars 
1687var jQuery = window.jQuery; 
1688var getComputedStyle = window.getComputedStyle; 
1689var console = window.console; 
1690 
1691function moveElements( elems, toElem ) { 
1692  elems = utils.makeArray( elems ); 
1693  while ( elems.length ) { 
1694    toElem.appendChild( elems.shift() ); 
1695
1696
1697 
1698// -------------------------- Flickity -------------------------- // 
1699 
1700// globally unique identifiers 
1701var GUID = 0; 
1702// internal store of all Flickity intances 
1703var instances = {}; 
1704 
1705function Flickity( element, options ) { 
1706  var queryElement = utils.getQueryElement( element ); 
1707  if ( !queryElement ) { 
1708    if ( console ) { 
1709      console.error( 'Bad element for Flickity: ' + ( queryElement || element ) ); 
1710
1711    return; 
1712
1713  this.element = queryElement; 
1714  // do not initialize twice on same element 
1715  if ( this.element.flickityGUID ) { 
1716    var instance = instances[ this.element.flickityGUID ]; 
1717    if ( instance ) instance.option( options ); 
1718    return instance; 
1719
1720 
1721  // add jQuery 
1722  if ( jQuery ) { 
1723    this.$element = jQuery( this.element ); 
1724
1725  // options 
1726  this.options = utils.extend( {}, this.constructor.defaults ); 
1727  this.option( options ); 
1728 
1729  // kick things off 
1730  this._create(); 
1731
1732 
1733Flickity.defaults = { 
1734  accessibility: true, 
1735  // adaptiveHeight: false, 
1736  cellAlign: 'center', 
1737  // cellSelector: undefined, 
1738  // contain: false, 
1739  freeScrollFriction: 0.075, // friction when free-scrolling 
1740  friction: 0.28, // friction when selecting 
1741  namespaceJQueryEvents: true, 
1742  // initialIndex: 0, 
1743  percentPosition: true, 
1744  resize: true, 
1745  selectedAttraction: 0.025, 
1746  setGallerySize: true, 
1747  // watchCSS: false, 
1748  // wrapAround: false 
1749}; 
1750 
1751// hash of methods triggered on _create() 
1752Flickity.createMethods = []; 
1753 
1754var proto = Flickity.prototype; 
1755// inherit EventEmitter 
1756utils.extend( proto, EvEmitter.prototype ); 
1757 
1758proto._create = function() { 
1759  // add id for Flickity.data 
1760  var id = this.guid = ++GUID; 
1761  this.element.flickityGUID = id; // expando 
1762  instances[ id ] = this; // associate via id 
1763  // initial properties 
1764  this.selectedIndex = 0; 
1765  // how many frames slider has been in same position 
1766  this.restingFrames = 0; 
1767  // initial physics properties 
1768  this.x = 0; 
1769  this.velocity = 0; 
1770  this.originSide = this.options.rightToLeft ? 'right' : 'left'; 
1771  // create viewport & slider 
1772  this.viewport = document.createElement('div'); 
1773  this.viewport.className = 'flickity-viewport'; 
1774  this._createSlider(); 
1775 
1776  if ( this.options.resize || this.options.watchCSS ) { 
1777    window.addEventListener( 'resize', this ); 
1778
1779 
1780  // add listeners from on option 
1781  for ( var eventName in this.options.on ) { 
1782    var listener = this.options.on[ eventName ]; 
1783    this.on( eventName, listener ); 
1784
1785 
1786  Flickity.createMethods.forEach( function( method ) { 
1787    this[ method ](); 
1788  }, this ); 
1789 
1790  if ( this.options.watchCSS ) { 
1791    this.watchCSS(); 
1792  } else { 
1793    this.activate(); 
1794
1795 
1796}; 
1797 
1798/** 
1799 * set options 
1800 * @param {Object} opts - options to extend 
1801 */ 
1802proto.option = function( opts ) { 
1803  utils.extend( this.options, opts ); 
1804}; 
1805 
1806proto.activate = function() { 
1807  if ( this.isActive ) { 
1808    return; 
1809
1810  this.isActive = true; 
1811  this.element.classList.add('flickity-enabled'); 
1812  if ( this.options.rightToLeft ) { 
1813    this.element.classList.add('flickity-rtl'); 
1814
1815 
1816  this.getSize(); 
1817  // move initial cell elements so they can be loaded as cells 
1818  var cellElems = this._filterFindCellElements( this.element.children ); 
1819  moveElements( cellElems, this.slider ); 
1820  this.viewport.appendChild( this.slider ); 
1821  this.element.appendChild( this.viewport ); 
1822  // get cells from children 
1823  this.reloadCells(); 
1824 
1825  if ( this.options.accessibility ) { 
1826    // allow element to focusable 
1827    this.element.tabIndex = 0; 
1828    // listen for key presses 
1829    this.element.addEventListener( 'keydown', this ); 
1830
1831 
1832  this.emitEvent('activate'); 
1833  this.selectInitialIndex(); 
1834  // flag for initial activation, for using initialIndex 
1835  this.isInitActivated = true; 
1836  // ready event. #493 
1837  this.dispatchEvent('ready'); 
1838}; 
1839 
1840// slider positions the cells 
1841proto._createSlider = function() { 
1842  // slider element does all the positioning 
1843  var slider = document.createElement('div'); 
1844  slider.className = 'flickity-slider'; 
1845  slider.style[ this.originSide ] = 0; 
1846  this.slider = slider; 
1847}; 
1848 
1849proto._filterFindCellElements = function( elems ) { 
1850  return utils.filterFindElements( elems, this.options.cellSelector ); 
1851}; 
1852 
1853// goes through all children 
1854proto.reloadCells = function() { 
1855  // collection of item elements 
1856  this.cells = this._makeCells( this.slider.children ); 
1857  this.positionCells(); 
1858  this._getWrapShiftCells(); 
1859  this.setGallerySize(); 
1860}; 
1861 
1862/** 
1863 * turn elements into Flickity.Cells 
1864 * @param {[Array, NodeList, HTMLElement]} elems - elements to make into cells 
1865 * @returns {Array} items - collection of new Flickity Cells 
1866 */ 
1867proto._makeCells = function( elems ) { 
1868  var cellElems = this._filterFindCellElements( elems ); 
1869 
1870  // create new Flickity for collection 
1871  var cells = cellElems.map( function( cellElem ) { 
1872    return new Cell( cellElem, this ); 
1873  }, this ); 
1874 
1875  return cells; 
1876}; 
1877 
1878proto.getLastCell = function() { 
1879  return this.cells[ this.cells.length - 1 ]; 
1880}; 
1881 
1882proto.getLastSlide = function() { 
1883  return this.slides[ this.slides.length - 1 ]; 
1884}; 
1885 
1886// positions all cells 
1887proto.positionCells = function() { 
1888  // size all cells 
1889  this._sizeCells( this.cells ); 
1890  // position all cells 
1891  this._positionCells( 0 ); 
1892}; 
1893 
1894/** 
1895 * position certain cells 
1896 * @param {Integer} index - which cell to start with 
1897 */ 
1898proto._positionCells = function( index ) { 
1899  index = index || 0; 
1900  // also measure maxCellHeight 
1901  // start 0 if positioning all cells 
1902  this.maxCellHeight = index ? this.maxCellHeight || 0 : 0; 
1903  var cellX = 0; 
1904  // get cellX 
1905  if ( index > 0 ) { 
1906    var startCell = this.cells[ index - 1 ]; 
1907    cellX = startCell.x + startCell.size.outerWidth; 
1908
1909  var len = this.cells.length; 
1910  for ( var i = index; i < len; i++ ) { 
1911    var cell = this.cells[i]; 
1912    cell.setPosition( cellX ); 
1913    cellX += cell.size.outerWidth; 
1914    this.maxCellHeight = Math.max( cell.size.outerHeight, this.maxCellHeight ); 
1915
1916  // keep track of cellX for wrap-around 
1917  this.slideableWidth = cellX; 
1918  // slides 
1919  this.updateSlides(); 
1920  // contain slides target 
1921  this._containSlides(); 
1922  // update slidesWidth 
1923  this.slidesWidth = len ? this.getLastSlide().target - this.slides[0].target : 0; 
1924}; 
1925 
1926/** 
1927 * cell.getSize() on multiple cells 
1928 * @param {Array} cells - cells to size 
1929 */ 
1930proto._sizeCells = function( cells ) { 
1931  cells.forEach( function( cell ) { 
1932    cell.getSize(); 
1933  } ); 
1934}; 
1935 
1936// --------------------------  -------------------------- // 
1937 
1938proto.updateSlides = function() { 
1939  this.slides = []; 
1940  if ( !this.cells.length ) { 
1941    return; 
1942
1943 
1944  var slide = new Slide( this ); 
1945  this.slides.push( slide ); 
1946  var isOriginLeft = this.originSide == 'left'; 
1947  var nextMargin = isOriginLeft ? 'marginRight' : 'marginLeft'; 
1948 
1949  var canCellFit = this._getCanCellFit(); 
1950 
1951  this.cells.forEach( function( cell, i ) { 
1952    // just add cell if first cell in slide 
1953    if ( !slide.cells.length ) { 
1954      slide.addCell( cell ); 
1955      return; 
1956
1957 
1958    var slideWidth = ( slide.outerWidth - slide.firstMargin ) + 
1959      ( cell.size.outerWidth - cell.size[ nextMargin ] ); 
1960 
1961    if ( canCellFit.call( this, i, slideWidth ) ) { 
1962      slide.addCell( cell ); 
1963    } else { 
1964      // doesn't fit, new slide 
1965      slide.updateTarget(); 
1966 
1967      slide = new Slide( this ); 
1968      this.slides.push( slide ); 
1969      slide.addCell( cell ); 
1970
1971  }, this ); 
1972  // last slide 
1973  slide.updateTarget(); 
1974  // update .selectedSlide 
1975  this.updateSelectedSlide(); 
1976}; 
1977 
1978proto._getCanCellFit = function() { 
1979  var groupCells = this.options.groupCells; 
1980  if ( !groupCells ) { 
1981    return function() { 
1982      return false; 
1983    }; 
1984  } else if ( typeof groupCells == 'number' ) { 
1985    // group by number. 3 -> [0,1,2], [3,4,5], ... 
1986    var number = parseInt( groupCells, 10 ); 
1987    return function( i ) { 
1988      return ( i % number ) !== 0; 
1989    }; 
1990
1991  // default, group by width of slide 
1992  // parse '75% 
1993  var percentMatch = typeof groupCells == 'string' && 
1994    groupCells.match( /^(\d+)%$/ ); 
1995  var percent = percentMatch ? parseInt( percentMatch[1], 10 ) / 100 : 1; 
1996  return function( i, slideWidth ) { 
1997    /* eslint-disable-next-line no-invalid-this */ 
1998    return slideWidth <= ( this.size.innerWidth + 1 ) * percent; 
1999  }; 
2000}; 
2001 
2002// alias _init for jQuery plugin .flickity() 
2003proto._init = 
2004proto.reposition = function() { 
2005  this.positionCells(); 
2006  this.positionSliderAtSelected(); 
2007}; 
2008 
2009proto.getSize = function() { 
2010  this.size = getSize( this.element ); 
2011  this.setCellAlign(); 
2012  this.cursorPosition = this.size.innerWidth * this.cellAlign; 
2013}; 
2014 
2015var cellAlignShorthands = { 
2016  // cell align, then based on origin side 
2017  center: { 
2018    left: 0.5, 
2019    right: 0.5, 
2020  }, 
2021  left: { 
2022    left: 0, 
2023    right: 1, 
2024  }, 
2025  right: { 
2026    right: 0, 
2027    left: 1, 
2028  }, 
2029}; 
2030 
2031proto.setCellAlign = function() { 
2032  var shorthand = cellAlignShorthands[ this.options.cellAlign ]; 
2033  this.cellAlign = shorthand ? shorthand[ this.originSide ] : this.options.cellAlign; 
2034}; 
2035 
2036proto.setGallerySize = function() { 
2037  if ( this.options.setGallerySize ) { 
2038    var height = this.options.adaptiveHeight && this.selectedSlide ? 
2039      this.selectedSlide.height : this.maxCellHeight; 
2040    this.viewport.style.height = height + 'px'; 
2041
2042}; 
2043 
2044proto._getWrapShiftCells = function() { 
2045  // only for wrap-around 
2046  if ( !this.options.wrapAround ) { 
2047    return; 
2048
2049  // unshift previous cells 
2050  this._unshiftCells( this.beforeShiftCells ); 
2051  this._unshiftCells( this.afterShiftCells ); 
2052  // get before cells 
2053  // initial gap 
2054  var gapX = this.cursorPosition; 
2055  var cellIndex = this.cells.length - 1; 
2056  this.beforeShiftCells = this._getGapCells( gapX, cellIndex, -1 ); 
2057  // get after cells 
2058  // ending gap between last cell and end of gallery viewport 
2059  gapX = this.size.innerWidth - this.cursorPosition; 
2060  // start cloning at first cell, working forwards 
2061  this.afterShiftCells = this._getGapCells( gapX, 0, 1 ); 
2062}; 
2063 
2064proto._getGapCells = function( gapX, cellIndex, increment ) { 
2065  // keep adding cells until the cover the initial gap 
2066  var cells = []; 
2067  while ( gapX > 0 ) { 
2068    var cell = this.cells[ cellIndex ]; 
2069    if ( !cell ) { 
2070      break; 
2071
2072    cells.push( cell ); 
2073    cellIndex += increment; 
2074    gapX -= cell.size.outerWidth; 
2075
2076  return cells; 
2077}; 
2078 
2079// ----- contain ----- // 
2080 
2081// contain cell targets so no excess sliding 
2082proto._containSlides = function() { 
2083  if ( !this.options.contain || this.options.wrapAround || !this.cells.length ) { 
2084    return; 
2085
2086  var isRightToLeft = this.options.rightToLeft; 
2087  var beginMargin = isRightToLeft ? 'marginRight' : 'marginLeft'; 
2088  var endMargin = isRightToLeft ? 'marginLeft' : 'marginRight'; 
2089  var contentWidth = this.slideableWidth - this.getLastCell().size[ endMargin ]; 
2090  // content is less than gallery size 
2091  var isContentSmaller = contentWidth < this.size.innerWidth; 
2092  // bounds 
2093  var beginBound = this.cursorPosition + this.cells[0].size[ beginMargin ]; 
2094  var endBound = contentWidth - this.size.innerWidth * ( 1 - this.cellAlign ); 
2095  // contain each cell target 
2096  this.slides.forEach( function( slide ) { 
2097    if ( isContentSmaller ) { 
2098      // all cells fit inside gallery 
2099      slide.target = contentWidth * this.cellAlign; 
2100    } else { 
2101      // contain to bounds 
2102      slide.target = Math.max( slide.target, beginBound ); 
2103      slide.target = Math.min( slide.target, endBound ); 
2104
2105  }, this ); 
2106}; 
2107 
2108// -----  ----- // 
2109 
2110/** 
2111 * emits events via eventEmitter and jQuery events 
2112 * @param {String} type - name of event 
2113 * @param {Event} event - original event 
2114 * @param {Array} args - extra arguments 
2115 */ 
2116proto.dispatchEvent = function( type, event, args ) { 
2117  var emitArgs = event ? [ event ].concat( args ) : args; 
2118  this.emitEvent( type, emitArgs ); 
2119 
2120  if ( jQuery && this.$element ) { 
2121    // default trigger with type if no event 
2122    type += this.options.namespaceJQueryEvents ? '.flickity' : ''; 
2123    var $event = type; 
2124    if ( event ) { 
2125      // create jQuery event 
2126      var jQEvent = new jQuery.Event( event ); 
2127      jQEvent.type = type; 
2128      $event = jQEvent; 
2129
2130    this.$element.trigger( $event, args ); 
2131
2132}; 
2133 
2134// -------------------------- select -------------------------- // 
2135 
2136/** 
2137 * @param {Integer} index - index of the slide 
2138 * @param {Boolean} isWrap - will wrap-around to last/first if at the end 
2139 * @param {Boolean} isInstant - will immediately set position at selected cell 
2140 */ 
2141proto.select = function( index, isWrap, isInstant ) { 
2142  if ( !this.isActive ) { 
2143    return; 
2144
2145  index = parseInt( index, 10 ); 
2146  this._wrapSelect( index ); 
2147 
2148  if ( this.options.wrapAround || isWrap ) { 
2149    index = utils.modulo( index, this.slides.length ); 
2150
2151  // bail if invalid index 
2152  if ( !this.slides[ index ] ) { 
2153    return; 
2154
2155  var prevIndex = this.selectedIndex; 
2156  this.selectedIndex = index; 
2157  this.updateSelectedSlide(); 
2158  if ( isInstant ) { 
2159    this.positionSliderAtSelected(); 
2160  } else { 
2161    this.startAnimation(); 
2162
2163  if ( this.options.adaptiveHeight ) { 
2164    this.setGallerySize(); 
2165
2166  // events 
2167  this.dispatchEvent( 'select', null, [ index ] ); 
2168  // change event if new index 
2169  if ( index != prevIndex ) { 
2170    this.dispatchEvent( 'change', null, [ index ] ); 
2171
2172  // old v1 event name, remove in v3 
2173  this.dispatchEvent('cellSelect'); 
2174}; 
2175 
2176// wraps position for wrapAround, to move to closest slide. #113 
2177proto._wrapSelect = function( index ) { 
2178  var len = this.slides.length; 
2179  var isWrapping = this.options.wrapAround && len > 1; 
2180  if ( !isWrapping ) { 
2181    return index; 
2182
2183  var wrapIndex = utils.modulo( index, len ); 
2184  // go to shortest 
2185  var delta = Math.abs( wrapIndex - this.selectedIndex ); 
2186  var backWrapDelta = Math.abs( ( wrapIndex + len ) - this.selectedIndex ); 
2187  var forewardWrapDelta = Math.abs( ( wrapIndex - len ) - this.selectedIndex ); 
2188  if ( !this.isDragSelect && backWrapDelta < delta ) { 
2189    index += len; 
2190  } else if ( !this.isDragSelect && forewardWrapDelta < delta ) { 
2191    index -= len; 
2192
2193  // wrap position so slider is within normal area 
2194  if ( index < 0 ) { 
2195    this.x -= this.slideableWidth; 
2196  } else if ( index >= len ) { 
2197    this.x += this.slideableWidth; 
2198
2199}; 
2200 
2201proto.previous = function( isWrap, isInstant ) { 
2202  this.select( this.selectedIndex - 1, isWrap, isInstant ); 
2203}; 
2204 
2205proto.next = function( isWrap, isInstant ) { 
2206  this.select( this.selectedIndex + 1, isWrap, isInstant ); 
2207}; 
2208 
2209proto.updateSelectedSlide = function() { 
2210  var slide = this.slides[ this.selectedIndex ]; 
2211  // selectedIndex could be outside of slides, if triggered before resize() 
2212  if ( !slide ) { 
2213    return; 
2214
2215  // unselect previous selected slide 
2216  this.unselectSelectedSlide(); 
2217  // update new selected slide 
2218  this.selectedSlide = slide; 
2219  slide.select(); 
2220  this.selectedCells = slide.cells; 
2221  this.selectedElements = slide.getCellElements(); 
2222  // HACK: selectedCell & selectedElement is first cell in slide, backwards compatibility 
2223  // Remove in v3? 
2224  this.selectedCell = slide.cells[0]; 
2225  this.selectedElement = this.selectedElements[0]; 
2226}; 
2227 
2228proto.unselectSelectedSlide = function() { 
2229  if ( this.selectedSlide ) { 
2230    this.selectedSlide.unselect(); 
2231
2232}; 
2233 
2234proto.selectInitialIndex = function() { 
2235  var initialIndex = this.options.initialIndex; 
2236  // already activated, select previous selectedIndex 
2237  if ( this.isInitActivated ) { 
2238    this.select( this.selectedIndex, false, true ); 
2239    return; 
2240
2241  // select with selector string 
2242  if ( initialIndex && typeof initialIndex == 'string' ) { 
2243    var cell = this.queryCell( initialIndex ); 
2244    if ( cell ) { 
2245      this.selectCell( initialIndex, false, true ); 
2246      return; 
2247
2248
2249 
2250  var index = 0; 
2251  // select with number 
2252  if ( initialIndex && this.slides[ initialIndex ] ) { 
2253    index = initialIndex; 
2254
2255  // select instantly 
2256  this.select( index, false, true ); 
2257}; 
2258 
2259/** 
2260 * select slide from number or cell element 
2261 * @param {[Element, Number]} value - zero-based index or element to select 
2262 * @param {Boolean} isWrap - enables wrapping around for extra index 
2263 * @param {Boolean} isInstant - disables slide animation 
2264 */ 
2265proto.selectCell = function( value, isWrap, isInstant ) { 
2266  // get cell 
2267  var cell = this.queryCell( value ); 
2268  if ( !cell ) { 
2269    return; 
2270
2271 
2272  var index = this.getCellSlideIndex( cell ); 
2273  this.select( index, isWrap, isInstant ); 
2274}; 
2275 
2276proto.getCellSlideIndex = function( cell ) { 
2277  // get index of slides that has cell 
2278  for ( var i = 0; i < this.slides.length; i++ ) { 
2279    var slide = this.slides[i]; 
2280    var index = slide.cells.indexOf( cell ); 
2281    if ( index != -1 ) { 
2282      return i; 
2283
2284
2285}; 
2286 
2287// -------------------------- get cells -------------------------- // 
2288 
2289/** 
2290 * get Flickity.Cell, given an Element 
2291 * @param {Element} elem - matching cell element 
2292 * @returns {Flickity.Cell} cell - matching cell 
2293 */ 
2294proto.getCell = function( elem ) { 
2295  // loop through cells to get the one that matches 
2296  for ( var i = 0; i < this.cells.length; i++ ) { 
2297    var cell = this.cells[i]; 
2298    if ( cell.element == elem ) { 
2299      return cell; 
2300
2301
2302}; 
2303 
2304/** 
2305 * get collection of Flickity.Cells, given Elements 
2306 * @param {[Element, Array, NodeList]} elems - multiple elements 
2307 * @returns {Array} cells - Flickity.Cells 
2308 */ 
2309proto.getCells = function( elems ) { 
2310  elems = utils.makeArray( elems ); 
2311  var cells = []; 
2312  elems.forEach( function( elem ) { 
2313    var cell = this.getCell( elem ); 
2314    if ( cell ) { 
2315      cells.push( cell ); 
2316
2317  }, this ); 
2318  return cells; 
2319}; 
2320 
2321/** 
2322 * get cell elements 
2323 * @returns {Array} cellElems 
2324 */ 
2325proto.getCellElements = function() { 
2326  return this.cells.map( function( cell ) { 
2327    return cell.element; 
2328  } ); 
2329}; 
2330 
2331/** 
2332 * get parent cell from an element 
2333 * @param {Element} elem - child element 
2334 * @returns {Flickit.Cell} cell - parent cell 
2335 */ 
2336proto.getParentCell = function( elem ) { 
2337  // first check if elem is cell 
2338  var cell = this.getCell( elem ); 
2339  if ( cell ) { 
2340    return cell; 
2341
2342  // try to get parent cell elem 
2343  elem = utils.getParent( elem, '.flickity-slider > *' ); 
2344  return this.getCell( elem ); 
2345}; 
2346 
2347/** 
2348 * get cells adjacent to a slide 
2349 * @param {Integer} adjCount - number of adjacent slides 
2350 * @param {Integer} index - index of slide to start 
2351 * @returns {Array} cells - array of Flickity.Cells 
2352 */ 
2353proto.getAdjacentCellElements = function( adjCount, index ) { 
2354  if ( !adjCount ) { 
2355    return this.selectedSlide.getCellElements(); 
2356
2357  index = index === undefined ? this.selectedIndex : index; 
2358 
2359  var len = this.slides.length; 
2360  if ( 1 + ( adjCount * 2 ) >= len ) { 
2361    return this.getCellElements(); 
2362
2363 
2364  var cellElems = []; 
2365  for ( var i = index - adjCount; i <= index + adjCount; i++ ) { 
2366    var slideIndex = this.options.wrapAround ? utils.modulo( i, len ) : i; 
2367    var slide = this.slides[ slideIndex ]; 
2368    if ( slide ) { 
2369      cellElems = cellElems.concat( slide.getCellElements() ); 
2370
2371
2372  return cellElems; 
2373}; 
2374 
2375/** 
2376 * select slide from number or cell element 
2377 * @param {[Element, String, Number]} selector - element, selector string, or index 
2378 * @returns {Flickity.Cell} - matching cell 
2379 */ 
2380proto.queryCell = function( selector ) { 
2381  if ( typeof selector == 'number' ) { 
2382    // use number as index 
2383    return this.cells[ selector ]; 
2384
2385  if ( typeof selector == 'string' ) { 
2386    // do not select invalid selectors from hash: #123, #/. #791 
2387    if ( selector.match( /^[#.]?[\d/]/ ) ) { 
2388      return; 
2389
2390    // use string as selector, get element 
2391    selector = this.element.querySelector( selector ); 
2392
2393  // get cell from element 
2394  return this.getCell( selector ); 
2395}; 
2396 
2397// -------------------------- events -------------------------- // 
2398 
2399proto.uiChange = function() { 
2400  this.emitEvent('uiChange'); 
2401}; 
2402 
2403// keep focus on element when child UI elements are clicked 
2404proto.childUIPointerDown = function( event ) { 
2405  // HACK iOS does not allow touch events to bubble up?! 
2406  if ( event.type != 'touchstart' ) { 
2407    event.preventDefault(); 
2408
2409  this.focus(); 
2410}; 
2411 
2412// ----- resize ----- // 
2413 
2414proto.onresize = function() { 
2415  this.watchCSS(); 
2416  this.resize(); 
2417}; 
2418 
2419utils.debounceMethod( Flickity, 'onresize', 150 ); 
2420 
2421proto.resize = function() { 
2422  if ( !this.isActive ) { 
2423    return; 
2424
2425  this.getSize(); 
2426  // wrap values 
2427  if ( this.options.wrapAround ) { 
2428    this.x = utils.modulo( this.x, this.slideableWidth ); 
2429
2430  this.positionCells(); 
2431  this._getWrapShiftCells(); 
2432  this.setGallerySize(); 
2433  this.emitEvent('resize'); 
2434  // update selected index for group slides, instant 
2435  // TODO: position can be lost between groups of various numbers 
2436  var selectedElement = this.selectedElements && this.selectedElements[0]; 
2437  this.selectCell( selectedElement, false, true ); 
2438}; 
2439 
2440// watches the :after property, activates/deactivates 
2441proto.watchCSS = function() { 
2442  var watchOption = this.options.watchCSS; 
2443  if ( !watchOption ) { 
2444    return; 
2445
2446 
2447  var afterContent = getComputedStyle( this.element, ':after' ).content; 
2448  // activate if :after { content: 'flickity' } 
2449  if ( afterContent.indexOf('flickity') != -1 ) { 
2450    this.activate(); 
2451  } else { 
2452    this.deactivate(); 
2453
2454}; 
2455 
2456// ----- keydown ----- // 
2457 
2458// go previous/next if left/right keys pressed 
2459proto.onkeydown = function( event ) { 
2460  // only work if element is in focus 
2461  var isNotFocused = document.activeElement && document.activeElement != this.element; 
2462  if ( !this.options.accessibility || isNotFocused ) { 
2463    return; 
2464
2465 
2466  var handler = Flickity.keyboardHandlers[ event.keyCode ]; 
2467  if ( handler ) { 
2468    handler.call( this ); 
2469
2470}; 
2471 
2472Flickity.keyboardHandlers = { 
2473  // left arrow 
2474  37: function() { 
2475    var leftMethod = this.options.rightToLeft ? 'next' : 'previous'; 
2476    this.uiChange(); 
2477    this[ leftMethod ](); 
2478  }, 
2479  // right arrow 
2480  39: function() { 
2481    var rightMethod = this.options.rightToLeft ? 'previous' : 'next'; 
2482    this.uiChange(); 
2483    this[ rightMethod ](); 
2484  }, 
2485}; 
2486 
2487// ----- focus ----- // 
2488 
2489proto.focus = function() { 
2490  // TODO remove scrollTo once focus options gets more support 
2491  // https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus ... 
2492  //    #Browser_compatibility 
2493  var prevScrollY = window.pageYOffset; 
2494  this.element.focus({ preventScroll: true }); 
2495  // hack to fix scroll jump after focus, #76 
2496  if ( window.pageYOffset != prevScrollY ) { 
2497    window.scrollTo( window.pageXOffset, prevScrollY ); 
2498
2499}; 
2500 
2501// -------------------------- destroy -------------------------- // 
2502 
2503// deactivate all Flickity functionality, but keep stuff available 
2504proto.deactivate = function() { 
2505  if ( !this.isActive ) { 
2506    return; 
2507
2508  this.element.classList.remove('flickity-enabled'); 
2509  this.element.classList.remove('flickity-rtl'); 
2510  this.unselectSelectedSlide(); 
2511  // destroy cells 
2512  this.cells.forEach( function( cell ) { 
2513    cell.destroy(); 
2514  } ); 
2515  this.element.removeChild( this.viewport ); 
2516  // move child elements back into element 
2517  moveElements( this.slider.children, this.element ); 
2518  if ( this.options.accessibility ) { 
2519    this.element.removeAttribute('tabIndex'); 
2520    this.element.removeEventListener( 'keydown', this ); 
2521
2522  // set flags 
2523  this.isActive = false; 
2524  this.emitEvent('deactivate'); 
2525}; 
2526 
2527proto.destroy = function() { 
2528  this.deactivate(); 
2529  window.removeEventListener( 'resize', this ); 
2530  this.allOff(); 
2531  this.emitEvent('destroy'); 
2532  if ( jQuery && this.$element ) { 
2533    jQuery.removeData( this.element, 'flickity' ); 
2534
2535  delete this.element.flickityGUID; 
2536  delete instances[ this.guid ]; 
2537}; 
2538 
2539// -------------------------- prototype -------------------------- // 
2540 
2541utils.extend( proto, animatePrototype ); 
2542 
2543// -------------------------- extras -------------------------- // 
2544 
2545/** 
2546 * get Flickity instance from element 
2547 * @param {[Element, String]} elem - element or selector string 
2548 * @returns {Flickity} - Flickity instance 
2549 */ 
2550Flickity.data = function( elem ) { 
2551  elem = utils.getQueryElement( elem ); 
2552  var id = elem && elem.flickityGUID; 
2553  return id && instances[ id ]; 
2554}; 
2555 
2556utils.htmlInit( Flickity, 'flickity' ); 
2557 
2558if ( jQuery && jQuery.bridget ) { 
2559  jQuery.bridget( 'flickity', Flickity ); 
2560
2561 
2562// set internal jQuery, for Webpack + jQuery v3, #478 
2563Flickity.setJQuery = function( jq ) { 
2564  jQuery = jq; 
2565}; 
2566 
2567Flickity.Cell = Cell; 
2568Flickity.Slide = Slide; 
2569 
2570return Flickity; 
2571 
2572} ) ); 
2573 
2574/*! 
2575 * Unipointer v2.3.0 
2576 * base class for doing one thing with pointer event 
2577 * MIT license 
2578 */ 
2579 
2580/*jshint browser: true, undef: true, unused: true, strict: true */ 
2581 
2582( function( window, factory ) { 
2583  // universal module definition 
2584  /* jshint strict: false */ /*global define, module, require */ 
2585  if ( typeof define == 'function' && define.amd ) { 
2586    // AMD 
2587    define( 'unipointer/unipointer',[ 
2588      'ev-emitter/ev-emitter' 
2589    ], function( EvEmitter ) { 
2590      return factory( window, EvEmitter ); 
2591    }); 
2592  } else if ( typeof module == 'object' && module.exports ) { 
2593    // CommonJS 
2594    module.exports = factory( 
2595      window, 
2596      require('ev-emitter') 
2597    ); 
2598  } else { 
2599    // browser global 
2600    window.Unipointer = factory( 
2601      window, 
2602      window.EvEmitter 
2603    ); 
2604
2605 
2606}( window, function factory( window, EvEmitter ) { 
2607 
2608 
2609 
2610function noop() {} 
2611 
2612function Unipointer() {} 
2613 
2614// inherit EvEmitter 
2615var proto = Unipointer.prototype = Object.create( EvEmitter.prototype ); 
2616 
2617proto.bindStartEvent = function( elem ) { 
2618  this._bindStartEvent( elem, true ); 
2619}; 
2620 
2621proto.unbindStartEvent = function( elem ) { 
2622  this._bindStartEvent( elem, false ); 
2623}; 
2624 
2625/** 
2626 * Add or remove start event 
2627 * @param {Boolean} isAdd - remove if falsey 
2628 */ 
2629proto._bindStartEvent = function( elem, isAdd ) { 
2630  // munge isAdd, default to true 
2631  isAdd = isAdd === undefined ? true : isAdd; 
2632  var bindMethod = isAdd ? 'addEventListener' : 'removeEventListener'; 
2633 
2634  // default to mouse events 
2635  var startEvent = 'mousedown'; 
2636  if ( window.PointerEvent ) { 
2637    // Pointer Events 
2638    startEvent = 'pointerdown'; 
2639  } else if ( 'ontouchstart' in window ) { 
2640    // Touch Events. iOS Safari 
2641    startEvent = 'touchstart'; 
2642
2643  elem[ bindMethod ]( startEvent, this ); 
2644}; 
2645 
2646// trigger handler methods for events 
2647proto.handleEvent = function( event ) { 
2648  var method = 'on' + event.type; 
2649  if ( this[ method ] ) { 
2650    this[ method ]( event ); 
2651
2652}; 
2653 
2654// returns the touch that we're keeping track of 
2655proto.getTouch = function( touches ) { 
2656  for ( var i=0; i < touches.length; i++ ) { 
2657    var touch = touches[i]; 
2658    if ( touch.identifier == this.pointerIdentifier ) { 
2659      return touch; 
2660
2661
2662}; 
2663 
2664// ----- start event ----- // 
2665 
2666proto.onmousedown = function( event ) { 
2667  // dismiss clicks from right or middle buttons 
2668  var button = event.button; 
2669  if ( button && ( button !== 0 && button !== 1 ) ) { 
2670    return; 
2671
2672  this._pointerDown( event, event ); 
2673}; 
2674 
2675proto.ontouchstart = function( event ) { 
2676  this._pointerDown( event, event.changedTouches[0] ); 
2677}; 
2678 
2679proto.onpointerdown = function( event ) { 
2680  this._pointerDown( event, event ); 
2681}; 
2682 
2683/** 
2684 * pointer start 
2685 * @param {Event} event 
2686 * @param {Event or Touch} pointer 
2687 */ 
2688proto._pointerDown = function( event, pointer ) { 
2689  // dismiss right click and other pointers 
2690  // button = 0 is okay, 1-4 not 
2691  if ( event.button || this.isPointerDown ) { 
2692    return; 
2693
2694 
2695  this.isPointerDown = true; 
2696  // save pointer identifier to match up touch events 
2697  this.pointerIdentifier = pointer.pointerId !== undefined ? 
2698    // pointerId for pointer events, touch.indentifier for touch events 
2699    pointer.pointerId : pointer.identifier; 
2700 
2701  this.pointerDown( event, pointer ); 
2702}; 
2703 
2704proto.pointerDown = function( event, pointer ) { 
2705  this._bindPostStartEvents( event ); 
2706  this.emitEvent( 'pointerDown', [ event, pointer ] ); 
2707}; 
2708 
2709// hash of events to be bound after start event 
2710var postStartEvents = { 
2711  mousedown: [ 'mousemove', 'mouseup' ], 
2712  touchstart: [ 'touchmove', 'touchend', 'touchcancel' ], 
2713  pointerdown: [ 'pointermove', 'pointerup', 'pointercancel' ], 
2714}; 
2715 
2716proto._bindPostStartEvents = function( event ) { 
2717  if ( !event ) { 
2718    return; 
2719
2720  // get proper events to match start event 
2721  var events = postStartEvents[ event.type ]; 
2722  // bind events to node 
2723  events.forEach( function( eventName ) { 
2724    window.addEventListener( eventName, this ); 
2725  }, this ); 
2726  // save these arguments 
2727  this._boundPointerEvents = events; 
2728}; 
2729 
2730proto._unbindPostStartEvents = function() { 
2731  // check for _boundEvents, in case dragEnd triggered twice (old IE8 bug) 
2732  if ( !this._boundPointerEvents ) { 
2733    return; 
2734
2735  this._boundPointerEvents.forEach( function( eventName ) { 
2736    window.removeEventListener( eventName, this ); 
2737  }, this ); 
2738 
2739  delete this._boundPointerEvents; 
2740}; 
2741 
2742// ----- move event ----- // 
2743 
2744proto.onmousemove = function( event ) { 
2745  this._pointerMove( event, event ); 
2746}; 
2747 
2748proto.onpointermove = function( event ) { 
2749  if ( event.pointerId == this.pointerIdentifier ) { 
2750    this._pointerMove( event, event ); 
2751
2752}; 
2753 
2754proto.ontouchmove = function( event ) { 
2755  var touch = this.getTouch( event.changedTouches ); 
2756  if ( touch ) { 
2757    this._pointerMove( event, touch ); 
2758
2759}; 
2760 
2761/** 
2762 * pointer move 
2763 * @param {Event} event 
2764 * @param {Event or Touch} pointer 
2765 * @private 
2766 */ 
2767proto._pointerMove = function( event, pointer ) { 
2768  this.pointerMove( event, pointer ); 
2769}; 
2770 
2771// public 
2772proto.pointerMove = function( event, pointer ) { 
2773  this.emitEvent( 'pointerMove', [ event, pointer ] ); 
2774}; 
2775 
2776// ----- end event ----- // 
2777 
2778 
2779proto.onmouseup = function( event ) { 
2780  this._pointerUp( event, event ); 
2781}; 
2782 
2783proto.onpointerup = function( event ) { 
2784  if ( event.pointerId == this.pointerIdentifier ) { 
2785    this._pointerUp( event, event ); 
2786
2787}; 
2788 
2789proto.ontouchend = function( event ) { 
2790  var touch = this.getTouch( event.changedTouches ); 
2791  if ( touch ) { 
2792    this._pointerUp( event, touch ); 
2793
2794}; 
2795 
2796/** 
2797 * pointer up 
2798 * @param {Event} event 
2799 * @param {Event or Touch} pointer 
2800 * @private 
2801 */ 
2802proto._pointerUp = function( event, pointer ) { 
2803  this._pointerDone(); 
2804  this.pointerUp( event, pointer ); 
2805}; 
2806 
2807// public 
2808proto.pointerUp = function( event, pointer ) { 
2809  this.emitEvent( 'pointerUp', [ event, pointer ] ); 
2810}; 
2811 
2812// ----- pointer done ----- // 
2813 
2814// triggered on pointer up & pointer cancel 
2815proto._pointerDone = function() { 
2816  this._pointerReset(); 
2817  this._unbindPostStartEvents(); 
2818  this.pointerDone(); 
2819}; 
2820 
2821proto._pointerReset = function() { 
2822  // reset properties 
2823  this.isPointerDown = false; 
2824  delete this.pointerIdentifier; 
2825}; 
2826 
2827proto.pointerDone = noop; 
2828 
2829// ----- pointer cancel ----- // 
2830 
2831proto.onpointercancel = function( event ) { 
2832  if ( event.pointerId == this.pointerIdentifier ) { 
2833    this._pointerCancel( event, event ); 
2834
2835}; 
2836 
2837proto.ontouchcancel = function( event ) { 
2838  var touch = this.getTouch( event.changedTouches ); 
2839  if ( touch ) { 
2840    this._pointerCancel( event, touch ); 
2841
2842}; 
2843 
2844/** 
2845 * pointer cancel 
2846 * @param {Event} event 
2847 * @param {Event or Touch} pointer 
2848 * @private 
2849 */ 
2850proto._pointerCancel = function( event, pointer ) { 
2851  this._pointerDone(); 
2852  this.pointerCancel( event, pointer ); 
2853}; 
2854 
2855// public 
2856proto.pointerCancel = function( event, pointer ) { 
2857  this.emitEvent( 'pointerCancel', [ event, pointer ] ); 
2858}; 
2859 
2860// -----  ----- // 
2861 
2862// utility function for getting x/y coords from event 
2863Unipointer.getPointerPoint = function( pointer ) { 
2864  return { 
2865    x: pointer.pageX, 
2866    y: pointer.pageY 
2867  }; 
2868}; 
2869 
2870// -----  ----- // 
2871 
2872return Unipointer; 
2873 
2874})); 
2875 
2876/*! 
2877 * Unidragger v2.3.1 
2878 * Draggable base class 
2879 * MIT license 
2880 */ 
2881 
2882/*jshint browser: true, unused: true, undef: true, strict: true */ 
2883 
2884( function( window, factory ) { 
2885  // universal module definition 
2886  /*jshint strict: false */ /*globals define, module, require */ 
2887 
2888  if ( typeof define == 'function' && define.amd ) { 
2889    // AMD 
2890    define( 'unidragger/unidragger',[ 
2891      'unipointer/unipointer' 
2892    ], function( Unipointer ) { 
2893      return factory( window, Unipointer ); 
2894    }); 
2895  } else if ( typeof module == 'object' && module.exports ) { 
2896    // CommonJS 
2897    module.exports = factory( 
2898      window, 
2899      require('unipointer') 
2900    ); 
2901  } else { 
2902    // browser global 
2903    window.Unidragger = factory( 
2904      window, 
2905      window.Unipointer 
2906    ); 
2907
2908 
2909}( window, function factory( window, Unipointer ) { 
2910 
2911 
2912 
2913// -------------------------- Unidragger -------------------------- // 
2914 
2915function Unidragger() {} 
2916 
2917// inherit Unipointer & EvEmitter 
2918var proto = Unidragger.prototype = Object.create( Unipointer.prototype ); 
2919 
2920// ----- bind start ----- // 
2921 
2922proto.bindHandles = function() { 
2923  this._bindHandles( true ); 
2924}; 
2925 
2926proto.unbindHandles = function() { 
2927  this._bindHandles( false ); 
2928}; 
2929 
2930/** 
2931 * Add or remove start event 
2932 * @param {Boolean} isAdd 
2933 */ 
2934proto._bindHandles = function( isAdd ) { 
2935  // munge isAdd, default to true 
2936  isAdd = isAdd === undefined ? true : isAdd; 
2937  // bind each handle 
2938  var bindMethod = isAdd ? 'addEventListener' : 'removeEventListener'; 
2939  var touchAction = isAdd ? this._touchActionValue : ''; 
2940  for ( var i=0; i < this.handles.length; i++ ) { 
2941    var handle = this.handles[i]; 
2942    this._bindStartEvent( handle, isAdd ); 
2943    handle[ bindMethod ]( 'click', this ); 
2944    // touch-action: none to override browser touch gestures. metafizzy/flickity#540 
2945    if ( window.PointerEvent ) { 
2946      handle.style.touchAction = touchAction; 
2947
2948
2949}; 
2950 
2951// prototype so it can be overwriteable by Flickity 
2952proto._touchActionValue = 'none'; 
2953 
2954// ----- start event ----- // 
2955 
2956/** 
2957 * pointer start 
2958 * @param {Event} event 
2959 * @param {Event or Touch} pointer 
2960 */ 
2961proto.pointerDown = function( event, pointer ) { 
2962  var isOkay = this.okayPointerDown( event ); 
2963  if ( !isOkay ) { 
2964    return; 
2965
2966  // track start event position 
2967  // Safari 9 overrides pageX and pageY. These values needs to be copied. flickity#842 
2968  this.pointerDownPointer = { 
2969    pageX: pointer.pageX, 
2970    pageY: pointer.pageY, 
2971  }; 
2972 
2973  event.preventDefault(); 
2974  this.pointerDownBlur(); 
2975  // bind move and end events 
2976  this._bindPostStartEvents( event ); 
2977  this.emitEvent( 'pointerDown', [ event, pointer ] ); 
2978}; 
2979 
2980// nodes that have text fields 
2981var cursorNodes = { 
2982  TEXTAREA: true, 
2983  INPUT: true, 
2984  SELECT: true, 
2985  OPTION: true, 
2986}; 
2987 
2988// input types that do not have text fields 
2989var clickTypes = { 
2990  radio: true, 
2991  checkbox: true, 
2992  button: true, 
2993  submit: true, 
2994  image: true, 
2995  file: true, 
2996}; 
2997 
2998// dismiss inputs with text fields. flickity#403, flickity#404 
2999proto.okayPointerDown = function( event ) { 
3000  var isCursorNode = cursorNodes[ event.target.nodeName ]; 
3001  var isClickType = clickTypes[ event.target.type ]; 
3002  var isOkay = !isCursorNode || isClickType; 
3003  if ( !isOkay ) { 
3004    this._pointerReset(); 
3005
3006  return isOkay; 
3007}; 
3008 
3009// kludge to blur previously focused input 
3010proto.pointerDownBlur = function() { 
3011  var focused = document.activeElement; 
3012  // do not blur body for IE10, metafizzy/flickity#117 
3013  var canBlur = focused && focused.blur && focused != document.body; 
3014  if ( canBlur ) { 
3015    focused.blur(); 
3016
3017}; 
3018 
3019// ----- move event ----- // 
3020 
3021/** 
3022 * drag move 
3023 * @param {Event} event 
3024 * @param {Event or Touch} pointer 
3025 */ 
3026proto.pointerMove = function( event, pointer ) { 
3027  var moveVector = this._dragPointerMove( event, pointer ); 
3028  this.emitEvent( 'pointerMove', [ event, pointer, moveVector ] ); 
3029  this._dragMove( event, pointer, moveVector ); 
3030}; 
3031 
3032// base pointer move logic 
3033proto._dragPointerMove = function( event, pointer ) { 
3034  var moveVector = { 
3035    x: pointer.pageX - this.pointerDownPointer.pageX, 
3036    y: pointer.pageY - this.pointerDownPointer.pageY 
3037  }; 
3038  // start drag if pointer has moved far enough to start drag 
3039  if ( !this.isDragging && this.hasDragStarted( moveVector ) ) { 
3040    this._dragStart( event, pointer ); 
3041
3042  return moveVector; 
3043}; 
3044 
3045// condition if pointer has moved far enough to start drag 
3046proto.hasDragStarted = function( moveVector ) { 
3047  return Math.abs( moveVector.x ) > 3 || Math.abs( moveVector.y ) > 3; 
3048}; 
3049 
3050// ----- end event ----- // 
3051 
3052/** 
3053 * pointer up 
3054 * @param {Event} event 
3055 * @param {Event or Touch} pointer 
3056 */ 
3057proto.pointerUp = function( event, pointer ) { 
3058  this.emitEvent( 'pointerUp', [ event, pointer ] ); 
3059  this._dragPointerUp( event, pointer ); 
3060}; 
3061 
3062proto._dragPointerUp = function( event, pointer ) { 
3063  if ( this.isDragging ) { 
3064    this._dragEnd( event, pointer ); 
3065  } else { 
3066    // pointer didn't move enough for drag to start 
3067    this._staticClick( event, pointer ); 
3068
3069}; 
3070 
3071// -------------------------- drag -------------------------- // 
3072 
3073// dragStart 
3074proto._dragStart = function( event, pointer ) { 
3075  this.isDragging = true; 
3076  // prevent clicks 
3077  this.isPreventingClicks = true; 
3078  this.dragStart( event, pointer ); 
3079}; 
3080 
3081proto.dragStart = function( event, pointer ) { 
3082  this.emitEvent( 'dragStart', [ event, pointer ] ); 
3083}; 
3084 
3085// dragMove 
3086proto._dragMove = function( event, pointer, moveVector ) { 
3087  // do not drag if not dragging yet 
3088  if ( !this.isDragging ) { 
3089    return; 
3090
3091 
3092  this.dragMove( event, pointer, moveVector ); 
3093}; 
3094 
3095proto.dragMove = function( event, pointer, moveVector ) { 
3096  event.preventDefault(); 
3097  this.emitEvent( 'dragMove', [ event, pointer, moveVector ] ); 
3098}; 
3099 
3100// dragEnd 
3101proto._dragEnd = function( event, pointer ) { 
3102  // set flags 
3103  this.isDragging = false; 
3104  // re-enable clicking async 
3105  setTimeout( function() { 
3106    delete this.isPreventingClicks; 
3107  }.bind( this ) ); 
3108 
3109  this.dragEnd( event, pointer ); 
3110}; 
3111 
3112proto.dragEnd = function( event, pointer ) { 
3113  this.emitEvent( 'dragEnd', [ event, pointer ] ); 
3114}; 
3115 
3116// ----- onclick ----- // 
3117 
3118// handle all clicks and prevent clicks when dragging 
3119proto.onclick = function( event ) { 
3120  if ( this.isPreventingClicks ) { 
3121    event.preventDefault(); 
3122
3123}; 
3124 
3125// ----- staticClick ----- // 
3126 
3127// triggered after pointer down & up with no/tiny movement 
3128proto._staticClick = function( event, pointer ) { 
3129  // ignore emulated mouse up clicks 
3130  if ( this.isIgnoringMouseUp && event.type == 'mouseup' ) { 
3131    return; 
3132
3133 
3134  this.staticClick( event, pointer ); 
3135 
3136  // set flag for emulated clicks 300ms after touchend 
3137  if ( event.type != 'mouseup' ) { 
3138    this.isIgnoringMouseUp = true; 
3139    // reset flag after 300ms 
3140    setTimeout( function() { 
3141      delete this.isIgnoringMouseUp; 
3142    }.bind( this ), 400 ); 
3143
3144}; 
3145 
3146proto.staticClick = function( event, pointer ) { 
3147  this.emitEvent( 'staticClick', [ event, pointer ] ); 
3148}; 
3149 
3150// ----- utils ----- // 
3151 
3152Unidragger.getPointerPoint = Unipointer.getPointerPoint; 
3153 
3154// -----  ----- // 
3155 
3156return Unidragger; 
3157 
3158})); 
3159 
3160// drag 
3161( function( window, factory ) { 
3162  // universal module definition 
3163  if ( typeof define == 'function' && define.amd ) { 
3164    // AMD 
3165    define( 'flickity/js/drag',[ 
3166      './flickity', 
3167      'unidragger/unidragger', 
3168      'fizzy-ui-utils/utils', 
3169    ], function( Flickity, Unidragger, utils ) { 
3170      return factory( window, Flickity, Unidragger, utils ); 
3171    } ); 
3172  } else if ( typeof module == 'object' && module.exports ) { 
3173    // CommonJS 
3174    module.exports = factory( 
3175        window, 
3176        require('./flickity'), 
3177        require('unidragger'), 
3178        require('fizzy-ui-utils') 
3179    ); 
3180  } else { 
3181    // browser global 
3182    window.Flickity = factory( 
3183        window, 
3184        window.Flickity, 
3185        window.Unidragger, 
3186        window.fizzyUIUtils 
3187    ); 
3188
3189 
3190}( window, function factory( window, Flickity, Unidragger, utils ) { 
3191 
3192 
3193 
3194// ----- defaults ----- // 
3195 
3196utils.extend( Flickity.defaults, { 
3197  draggable: '>1', 
3198  dragThreshold: 3, 
3199} ); 
3200 
3201// ----- create ----- // 
3202 
3203Flickity.createMethods.push('_createDrag'); 
3204 
3205// -------------------------- drag prototype -------------------------- // 
3206 
3207var proto = Flickity.prototype; 
3208utils.extend( proto, Unidragger.prototype ); 
3209proto._touchActionValue = 'pan-y'; 
3210 
3211// --------------------------  -------------------------- // 
3212 
3213var isTouch = 'createTouch' in document; 
3214var isTouchmoveScrollCanceled = false; 
3215 
3216proto._createDrag = function() { 
3217  this.on( 'activate', this.onActivateDrag ); 
3218  this.on( 'uiChange', this._uiChangeDrag ); 
3219  this.on( 'deactivate', this.onDeactivateDrag ); 
3220  this.on( 'cellChange', this.updateDraggable ); 
3221  // TODO updateDraggable on resize? if groupCells & slides change 
3222  // HACK - add seemingly innocuous handler to fix iOS 10 scroll behavior 
3223  // #457, RubaXa/Sortable#973 
3224  if ( isTouch && !isTouchmoveScrollCanceled ) { 
3225    window.addEventListener( 'touchmove', function() {} ); 
3226    isTouchmoveScrollCanceled = true; 
3227
3228}; 
3229 
3230proto.onActivateDrag = function() { 
3231  this.handles = [ this.viewport ]; 
3232  this.bindHandles(); 
3233  this.updateDraggable(); 
3234}; 
3235 
3236proto.onDeactivateDrag = function() { 
3237  this.unbindHandles(); 
3238  this.element.classList.remove('is-draggable'); 
3239}; 
3240 
3241proto.updateDraggable = function() { 
3242  // disable dragging if less than 2 slides. #278 
3243  if ( this.options.draggable == '>1' ) { 
3244    this.isDraggable = this.slides.length > 1; 
3245  } else { 
3246    this.isDraggable = this.options.draggable; 
3247
3248  if ( this.isDraggable ) { 
3249    this.element.classList.add('is-draggable'); 
3250  } else { 
3251    this.element.classList.remove('is-draggable'); 
3252
3253}; 
3254 
3255// backwards compatibility 
3256proto.bindDrag = function() { 
3257  this.options.draggable = true; 
3258  this.updateDraggable(); 
3259}; 
3260 
3261proto.unbindDrag = function() { 
3262  this.options.draggable = false; 
3263  this.updateDraggable(); 
3264}; 
3265 
3266proto._uiChangeDrag = function() { 
3267  delete this.isFreeScrolling; 
3268}; 
3269 
3270// -------------------------- pointer events -------------------------- // 
3271 
3272proto.pointerDown = function( event, pointer ) { 
3273  if ( !this.isDraggable ) { 
3274    this._pointerDownDefault( event, pointer ); 
3275    return; 
3276
3277  var isOkay = this.okayPointerDown( event ); 
3278  if ( !isOkay ) { 
3279    return; 
3280
3281 
3282  this._pointerDownPreventDefault( event ); 
3283  this.pointerDownFocus( event ); 
3284  // blur 
3285  if ( document.activeElement != this.element ) { 
3286    // do not blur if already focused 
3287    this.pointerDownBlur(); 
3288
3289 
3290  // stop if it was moving 
3291  this.dragX = this.x; 
3292  this.viewport.classList.add('is-pointer-down'); 
3293  // track scrolling 
3294  this.pointerDownScroll = getScrollPosition(); 
3295  window.addEventListener( 'scroll', this ); 
3296 
3297  this._pointerDownDefault( event, pointer ); 
3298}; 
3299 
3300// default pointerDown logic, used for staticClick 
3301proto._pointerDownDefault = function( event, pointer ) { 
3302  // track start event position 
3303  // Safari 9 overrides pageX and pageY. These values needs to be copied. #779 
3304  this.pointerDownPointer = { 
3305    pageX: pointer.pageX, 
3306    pageY: pointer.pageY, 
3307  }; 
3308  // bind move and end events 
3309  this._bindPostStartEvents( event ); 
3310  this.dispatchEvent( 'pointerDown', event, [ pointer ] ); 
3311}; 
3312 
3313var focusNodes = { 
3314  INPUT: true, 
3315  TEXTAREA: true, 
3316  SELECT: true, 
3317}; 
3318 
3319proto.pointerDownFocus = function( event ) { 
3320  var isFocusNode = focusNodes[ event.target.nodeName ]; 
3321  if ( !isFocusNode ) { 
3322    this.focus(); 
3323
3324}; 
3325 
3326proto._pointerDownPreventDefault = function( event ) { 
3327  var isTouchStart = event.type == 'touchstart'; 
3328  var isTouchPointer = event.pointerType == 'touch'; 
3329  var isFocusNode = focusNodes[ event.target.nodeName ]; 
3330  if ( !isTouchStart && !isTouchPointer && !isFocusNode ) { 
3331    event.preventDefault(); 
3332
3333}; 
3334 
3335// ----- move ----- // 
3336 
3337proto.hasDragStarted = function( moveVector ) { 
3338  return Math.abs( moveVector.x ) > this.options.dragThreshold; 
3339}; 
3340 
3341// ----- up ----- // 
3342 
3343proto.pointerUp = function( event, pointer ) { 
3344  delete this.isTouchScrolling; 
3345  this.viewport.classList.remove('is-pointer-down'); 
3346  this.dispatchEvent( 'pointerUp', event, [ pointer ] ); 
3347  this._dragPointerUp( event, pointer ); 
3348}; 
3349 
3350proto.pointerDone = function() { 
3351  window.removeEventListener( 'scroll', this ); 
3352  delete this.pointerDownScroll; 
3353}; 
3354 
3355// -------------------------- dragging -------------------------- // 
3356 
3357proto.dragStart = function( event, pointer ) { 
3358  if ( !this.isDraggable ) { 
3359    return; 
3360
3361  this.dragStartPosition = this.x; 
3362  this.startAnimation(); 
3363  window.removeEventListener( 'scroll', this ); 
3364  this.dispatchEvent( 'dragStart', event, [ pointer ] ); 
3365}; 
3366 
3367proto.pointerMove = function( event, pointer ) { 
3368  var moveVector = this._dragPointerMove( event, pointer ); 
3369  this.dispatchEvent( 'pointerMove', event, [ pointer, moveVector ] ); 
3370  this._dragMove( event, pointer, moveVector ); 
3371}; 
3372 
3373proto.dragMove = function( event, pointer, moveVector ) { 
3374  if ( !this.isDraggable ) { 
3375    return; 
3376
3377  event.preventDefault(); 
3378 
3379  this.previousDragX = this.dragX; 
3380  // reverse if right-to-left 
3381  var direction = this.options.rightToLeft ? -1 : 1; 
3382  if ( this.options.wrapAround ) { 
3383    // wrap around move. #589 
3384    moveVector.x %= this.slideableWidth; 
3385
3386  var dragX = this.dragStartPosition + moveVector.x * direction; 
3387 
3388  if ( !this.options.wrapAround && this.slides.length ) { 
3389    // slow drag 
3390    var originBound = Math.max( -this.slides[0].target, this.dragStartPosition ); 
3391    dragX = dragX > originBound ? ( dragX + originBound ) * 0.5 : dragX; 
3392    var endBound = Math.min( -this.getLastSlide().target, this.dragStartPosition ); 
3393    dragX = dragX < endBound ? ( dragX + endBound ) * 0.5 : dragX; 
3394
3395 
3396  this.dragX = dragX; 
3397 
3398  this.dragMoveTime = new Date(); 
3399  this.dispatchEvent( 'dragMove', event, [ pointer, moveVector ] ); 
3400}; 
3401 
3402proto.dragEnd = function( event, pointer ) { 
3403  if ( !this.isDraggable ) { 
3404    return; 
3405
3406  if ( this.options.freeScroll ) { 
3407    this.isFreeScrolling = true; 
3408
3409  // set selectedIndex based on where flick will end up 
3410  var index = this.dragEndRestingSelect(); 
3411 
3412  if ( this.options.freeScroll && !this.options.wrapAround ) { 
3413    // if free-scroll & not wrap around 
3414    // do not free-scroll if going outside of bounding slides 
3415    // so bounding slides can attract slider, and keep it in bounds 
3416    var restingX = this.getRestingPosition(); 
3417    this.isFreeScrolling = -restingX > this.slides[0].target && 
3418      -restingX < this.getLastSlide().target; 
3419  } else if ( !this.options.freeScroll && index == this.selectedIndex ) { 
3420    // boost selection if selected index has not changed 
3421    index += this.dragEndBoostSelect(); 
3422
3423  delete this.previousDragX; 
3424  // apply selection 
3425  // TODO refactor this, selecting here feels weird 
3426  // HACK, set flag so dragging stays in correct direction 
3427  this.isDragSelect = this.options.wrapAround; 
3428  this.select( index ); 
3429  delete this.isDragSelect; 
3430  this.dispatchEvent( 'dragEnd', event, [ pointer ] ); 
3431}; 
3432 
3433proto.dragEndRestingSelect = function() { 
3434  var restingX = this.getRestingPosition(); 
3435  // how far away from selected slide 
3436  var distance = Math.abs( this.getSlideDistance( -restingX, this.selectedIndex ) ); 
3437  // get closet resting going up and going down 
3438  var positiveResting = this._getClosestResting( restingX, distance, 1 ); 
3439  var negativeResting = this._getClosestResting( restingX, distance, -1 ); 
3440  // use closer resting for wrap-around 
3441  var index = positiveResting.distance < negativeResting.distance ? 
3442    positiveResting.index : negativeResting.index; 
3443  return index; 
3444}; 
3445 
3446/** 
3447 * given resting X and distance to selected cell 
3448 * get the distance and index of the closest cell 
3449 * @param {Number} restingX - estimated post-flick resting position 
3450 * @param {Number} distance - distance to selected cell 
3451 * @param {Integer} increment - +1 or -1, going up or down 
3452 * @returns {Object} - { distance: {Number}, index: {Integer} } 
3453 */ 
3454proto._getClosestResting = function( restingX, distance, increment ) { 
3455  var index = this.selectedIndex; 
3456  var minDistance = Infinity; 
3457  var condition = this.options.contain && !this.options.wrapAround ? 
3458    // if contain, keep going if distance is equal to minDistance 
3459    function( dist, minDist ) { 
3460      return dist <= minDist; 
3461    } : function( dist, minDist ) { 
3462      return dist < minDist; 
3463    }; 
3464  while ( condition( distance, minDistance ) ) { 
3465    // measure distance to next cell 
3466    index += increment; 
3467    minDistance = distance; 
3468    distance = this.getSlideDistance( -restingX, index ); 
3469    if ( distance === null ) { 
3470      break; 
3471
3472    distance = Math.abs( distance ); 
3473
3474  return { 
3475    distance: minDistance, 
3476    // selected was previous index 
3477    index: index - increment, 
3478  }; 
3479}; 
3480 
3481/** 
3482 * measure distance between x and a slide target 
3483 * @param {Number} x - horizontal position 
3484 * @param {Integer} index - slide index 
3485 * @returns {Number} - slide distance 
3486 */ 
3487proto.getSlideDistance = function( x, index ) { 
3488  var len = this.slides.length; 
3489  // wrap around if at least 2 slides 
3490  var isWrapAround = this.options.wrapAround && len > 1; 
3491  var slideIndex = isWrapAround ? utils.modulo( index, len ) : index; 
3492  var slide = this.slides[ slideIndex ]; 
3493  if ( !slide ) { 
3494    return null; 
3495
3496  // add distance for wrap-around slides 
3497  var wrap = isWrapAround ? this.slideableWidth * Math.floor( index/len ) : 0; 
3498  return x - ( slide.target + wrap ); 
3499}; 
3500 
3501proto.dragEndBoostSelect = function() { 
3502  // do not boost if no previousDragX or dragMoveTime 
3503  if ( this.previousDragX === undefined || !this.dragMoveTime || 
3504    // or if drag was held for 100 ms 
3505    new Date() - this.dragMoveTime > 100 ) { 
3506    return 0; 
3507
3508 
3509  var distance = this.getSlideDistance( -this.dragX, this.selectedIndex ); 
3510  var delta = this.previousDragX - this.dragX; 
3511  if ( distance > 0 && delta > 0 ) { 
3512    // boost to next if moving towards the right, and positive velocity 
3513    return 1; 
3514  } else if ( distance < 0 && delta < 0 ) { 
3515    // boost to previous if moving towards the left, and negative velocity 
3516    return -1; 
3517
3518  return 0; 
3519}; 
3520 
3521// ----- staticClick ----- // 
3522 
3523proto.staticClick = function( event, pointer ) { 
3524  // get clickedCell, if cell was clicked 
3525  var clickedCell = this.getParentCell( event.target ); 
3526  var cellElem = clickedCell && clickedCell.element; 
3527  var cellIndex = clickedCell && this.cells.indexOf( clickedCell ); 
3528  this.dispatchEvent( 'staticClick', event, [ pointer, cellElem, cellIndex ] ); 
3529}; 
3530 
3531// ----- scroll ----- // 
3532 
3533proto.onscroll = function() { 
3534  var scroll = getScrollPosition(); 
3535  var scrollMoveX = this.pointerDownScroll.x - scroll.x; 
3536  var scrollMoveY = this.pointerDownScroll.y - scroll.y; 
3537  // cancel click/tap if scroll is too much 
3538  if ( Math.abs( scrollMoveX ) > 3 || Math.abs( scrollMoveY ) > 3 ) { 
3539    this._pointerDone(); 
3540
3541}; 
3542 
3543// ----- utils ----- // 
3544 
3545function getScrollPosition() { 
3546  return { 
3547    x: window.pageXOffset, 
3548    y: window.pageYOffset, 
3549  }; 
3550
3551 
3552// -----  ----- // 
3553 
3554return Flickity; 
3555 
3556} ) ); 
3557 
3558// prev/next buttons 
3559( function( window, factory ) { 
3560  // universal module definition 
3561  if ( typeof define == 'function' && define.amd ) { 
3562    // AMD 
3563    define( 'flickity/js/prev-next-button',[ 
3564      './flickity', 
3565      'unipointer/unipointer', 
3566      'fizzy-ui-utils/utils', 
3567    ], function( Flickity, Unipointer, utils ) { 
3568      return factory( window, Flickity, Unipointer, utils ); 
3569    } ); 
3570  } else if ( typeof module == 'object' && module.exports ) { 
3571    // CommonJS 
3572    module.exports = factory( 
3573        window, 
3574        require('./flickity'), 
3575        require('unipointer'), 
3576        require('fizzy-ui-utils') 
3577    ); 
3578  } else { 
3579    // browser global 
3580    factory( 
3581        window, 
3582        window.Flickity, 
3583        window.Unipointer, 
3584        window.fizzyUIUtils 
3585    ); 
3586
3587 
3588}( window, function factory( window, Flickity, Unipointer, utils ) { 
3589'use strict'; 
3590 
3591var svgURI = 'http://www.w3.org/2000/svg'; 
3592 
3593// -------------------------- PrevNextButton -------------------------- // 
3594 
3595function PrevNextButton( direction, parent ) { 
3596  this.direction = direction; 
3597  this.parent = parent; 
3598  this._create(); 
3599
3600 
3601PrevNextButton.prototype = Object.create( Unipointer.prototype ); 
3602 
3603PrevNextButton.prototype._create = function() { 
3604  // properties 
3605  this.isEnabled = true; 
3606  this.isPrevious = this.direction == -1; 
3607  var leftDirection = this.parent.options.rightToLeft ? 1 : -1; 
3608  this.isLeft = this.direction == leftDirection; 
3609 
3610  var element = this.element = document.createElement('button'); 
3611  element.className = 'flickity-button flickity-prev-next-button'; 
3612  element.className += this.isPrevious ? ' previous' : ' next'; 
3613  // prevent button from submitting form http://stackoverflow.com/a/10836076/182183 
3614  element.setAttribute( 'type', 'button' ); 
3615  // init as disabled 
3616  this.disable(); 
3617 
3618  element.setAttribute( 'aria-label', this.isPrevious ? 'Previous' : 'Next' ); 
3619 
3620  // create arrow 
3621  var svg = this.createSVG(); 
3622  element.appendChild( svg ); 
3623  // events 
3624  this.parent.on( 'select', this.update.bind( this ) ); 
3625  this.on( 'pointerDown', this.parent.childUIPointerDown.bind( this.parent ) ); 
3626}; 
3627 
3628PrevNextButton.prototype.activate = function() { 
3629  this.bindStartEvent( this.element ); 
3630  this.element.addEventListener( 'click', this ); 
3631  // add to DOM 
3632  this.parent.element.appendChild( this.element ); 
3633}; 
3634 
3635PrevNextButton.prototype.deactivate = function() { 
3636  // remove from DOM 
3637  this.parent.element.removeChild( this.element ); 
3638  // click events 
3639  this.unbindStartEvent( this.element ); 
3640  this.element.removeEventListener( 'click', this ); 
3641}; 
3642 
3643PrevNextButton.prototype.createSVG = function() { 
3644  var svg = document.createElementNS( svgURI, 'svg' ); 
3645  svg.setAttribute( 'class', 'flickity-button-icon' ); 
3646  svg.setAttribute( 'viewBox', '0 0 100 100' ); 
3647  var path = document.createElementNS( svgURI, 'path' ); 
3648  var pathMovements = getArrowMovements( this.parent.options.arrowShape ); 
3649  path.setAttribute( 'd', pathMovements ); 
3650  path.setAttribute( 'class', 'arrow' ); 
3651  // rotate arrow 
3652  if ( !this.isLeft ) { 
3653    path.setAttribute( 'transform', 'translate(100, 100) rotate(180) ' ); 
3654
3655  svg.appendChild( path ); 
3656  return svg; 
3657}; 
3658 
3659// get SVG path movmement 
3660function getArrowMovements( shape ) { 
3661  // use shape as movement if string 
3662  if ( typeof shape == 'string' ) { 
3663    return shape; 
3664
3665  // create movement string 
3666  return 'M ' + shape.x0 + ',50' + 
3667    ' L ' + shape.x1 + ',' + ( shape.y1 + 50 ) + 
3668    ' L ' + shape.x2 + ',' + ( shape.y2 + 50 ) + 
3669    ' L ' + shape.x3 + ',50 ' + 
3670    ' L ' + shape.x2 + ',' + ( 50 - shape.y2 ) + 
3671    ' L ' + shape.x1 + ',' + ( 50 - shape.y1 ) + 
3672    ' Z'; 
3673
3674 
3675PrevNextButton.prototype.handleEvent = utils.handleEvent; 
3676 
3677PrevNextButton.prototype.onclick = function() { 
3678  if ( !this.isEnabled ) { 
3679    return; 
3680
3681  this.parent.uiChange(); 
3682  var method = this.isPrevious ? 'previous' : 'next'; 
3683  this.parent[ method ](); 
3684}; 
3685 
3686// -----  ----- // 
3687 
3688PrevNextButton.prototype.enable = function() { 
3689  if ( this.isEnabled ) { 
3690    return; 
3691
3692  this.element.disabled = false; 
3693  this.isEnabled = true; 
3694}; 
3695 
3696PrevNextButton.prototype.disable = function() { 
3697  if ( !this.isEnabled ) { 
3698    return; 
3699
3700  this.element.disabled = true; 
3701  this.isEnabled = false; 
3702}; 
3703 
3704PrevNextButton.prototype.update = function() { 
3705  // index of first or last slide, if previous or next 
3706  var slides = this.parent.slides; 
3707  // enable is wrapAround and at least 2 slides 
3708  if ( this.parent.options.wrapAround && slides.length > 1 ) { 
3709    this.enable(); 
3710    return; 
3711
3712  var lastIndex = slides.length ? slides.length - 1 : 0; 
3713  var boundIndex = this.isPrevious ? 0 : lastIndex; 
3714  var method = this.parent.selectedIndex == boundIndex ? 'disable' : 'enable'; 
3715  this[ method ](); 
3716}; 
3717 
3718PrevNextButton.prototype.destroy = function() { 
3719  this.deactivate(); 
3720  this.allOff(); 
3721}; 
3722 
3723// -------------------------- Flickity prototype -------------------------- // 
3724 
3725utils.extend( Flickity.defaults, { 
3726  prevNextButtons: true, 
3727  arrowShape: { 
3728    x0: 10, 
3729    x1: 60, y1: 50, 
3730    x2: 70, y2: 40, 
3731    x3: 30, 
3732  }, 
3733} ); 
3734 
3735Flickity.createMethods.push('_createPrevNextButtons'); 
3736var proto = Flickity.prototype; 
3737 
3738proto._createPrevNextButtons = function() { 
3739  if ( !this.options.prevNextButtons ) { 
3740    return; 
3741
3742 
3743  this.prevButton = new PrevNextButton( -1, this ); 
3744  this.nextButton = new PrevNextButton( 1, this ); 
3745 
3746  this.on( 'activate', this.activatePrevNextButtons ); 
3747}; 
3748 
3749proto.activatePrevNextButtons = function() { 
3750  this.prevButton.activate(); 
3751  this.nextButton.activate(); 
3752  this.on( 'deactivate', this.deactivatePrevNextButtons ); 
3753}; 
3754 
3755proto.deactivatePrevNextButtons = function() { 
3756  this.prevButton.deactivate(); 
3757  this.nextButton.deactivate(); 
3758  this.off( 'deactivate', this.deactivatePrevNextButtons ); 
3759}; 
3760 
3761// --------------------------  -------------------------- // 
3762 
3763Flickity.PrevNextButton = PrevNextButton; 
3764 
3765return Flickity; 
3766 
3767} ) ); 
3768 
3769// page dots 
3770( function( window, factory ) { 
3771  // universal module definition 
3772  if ( typeof define == 'function' && define.amd ) { 
3773    // AMD 
3774    define( 'flickity/js/page-dots',[ 
3775      './flickity', 
3776      'unipointer/unipointer', 
3777      'fizzy-ui-utils/utils', 
3778    ], function( Flickity, Unipointer, utils ) { 
3779      return factory( window, Flickity, Unipointer, utils ); 
3780    } ); 
3781  } else if ( typeof module == 'object' && module.exports ) { 
3782    // CommonJS 
3783    module.exports = factory( 
3784        window, 
3785        require('./flickity'), 
3786        require('unipointer'), 
3787        require('fizzy-ui-utils') 
3788    ); 
3789  } else { 
3790    // browser global 
3791    factory( 
3792        window, 
3793        window.Flickity, 
3794        window.Unipointer, 
3795        window.fizzyUIUtils 
3796    ); 
3797
3798 
3799}( window, function factory( window, Flickity, Unipointer, utils ) { 
3800 
3801// -------------------------- PageDots -------------------------- // 
3802 
3803 
3804 
3805function PageDots( parent ) { 
3806  this.parent = parent; 
3807  this._create(); 
3808
3809 
3810PageDots.prototype = Object.create( Unipointer.prototype ); 
3811 
3812PageDots.prototype._create = function() { 
3813  // create holder element 
3814  this.holder = document.createElement('ol'); 
3815  this.holder.className = 'flickity-page-dots'; 
3816  // create dots, array of elements 
3817  this.dots = []; 
3818  // events 
3819  this.handleClick = this.onClick.bind( this ); 
3820  this.on( 'pointerDown', this.parent.childUIPointerDown.bind( this.parent ) ); 
3821}; 
3822 
3823PageDots.prototype.activate = function() { 
3824  this.setDots(); 
3825  this.holder.addEventListener( 'click', this.handleClick ); 
3826  this.bindStartEvent( this.holder ); 
3827  // add to DOM 
3828  this.parent.element.appendChild( this.holder ); 
3829}; 
3830 
3831PageDots.prototype.deactivate = function() { 
3832  this.holder.removeEventListener( 'click', this.handleClick ); 
3833  this.unbindStartEvent( this.holder ); 
3834  // remove from DOM 
3835  this.parent.element.removeChild( this.holder ); 
3836}; 
3837 
3838PageDots.prototype.setDots = function() { 
3839  // get difference between number of slides and number of dots 
3840  var delta = this.parent.slides.length - this.dots.length; 
3841  if ( delta > 0 ) { 
3842    this.addDots( delta ); 
3843  } else if ( delta < 0 ) { 
3844    this.removeDots( -delta ); 
3845
3846}; 
3847 
3848PageDots.prototype.addDots = function( count ) { 
3849  var fragment = document.createDocumentFragment(); 
3850  var newDots = []; 
3851  var length = this.dots.length; 
3852  var max = length + count; 
3853 
3854  for ( var i = length; i < max; i++ ) { 
3855    var dot = document.createElement('li'); 
3856    dot.className = 'dot'; 
3857    dot.setAttribute( 'aria-label', 'Page dot ' + ( i + 1 ) ); 
3858    fragment.appendChild( dot ); 
3859    newDots.push( dot ); 
3860
3861 
3862  this.holder.appendChild( fragment ); 
3863  this.dots = this.dots.concat( newDots ); 
3864}; 
3865 
3866PageDots.prototype.removeDots = function( count ) { 
3867  // remove from this.dots collection 
3868  var removeDots = this.dots.splice( this.dots.length - count, count ); 
3869  // remove from DOM 
3870  removeDots.forEach( function( dot ) { 
3871    this.holder.removeChild( dot ); 
3872  }, this ); 
3873}; 
3874 
3875PageDots.prototype.updateSelected = function() { 
3876  // remove selected class on previous 
3877  if ( this.selectedDot ) { 
3878    this.selectedDot.className = 'dot'; 
3879    this.selectedDot.removeAttribute('aria-current'); 
3880
3881  // don't proceed if no dots 
3882  if ( !this.dots.length ) { 
3883    return; 
3884
3885  this.selectedDot = this.dots[ this.parent.selectedIndex ]; 
3886  this.selectedDot.className = 'dot is-selected'; 
3887  this.selectedDot.setAttribute( 'aria-current', 'step' ); 
3888}; 
3889 
3890PageDots.prototype.onTap = // old method name, backwards-compatible 
3891PageDots.prototype.onClick = function( event ) { 
3892  var target = event.target; 
3893  // only care about dot clicks 
3894  if ( target.nodeName != 'LI' ) { 
3895    return; 
3896
3897 
3898  this.parent.uiChange(); 
3899  var index = this.dots.indexOf( target ); 
3900  this.parent.select( index ); 
3901}; 
3902 
3903PageDots.prototype.destroy = function() { 
3904  this.deactivate(); 
3905  this.allOff(); 
3906}; 
3907 
3908Flickity.PageDots = PageDots; 
3909 
3910// -------------------------- Flickity -------------------------- // 
3911 
3912utils.extend( Flickity.defaults, { 
3913  pageDots: true, 
3914} ); 
3915 
3916Flickity.createMethods.push('_createPageDots'); 
3917 
3918var proto = Flickity.prototype; 
3919 
3920proto._createPageDots = function() { 
3921  if ( !this.options.pageDots ) { 
3922    return; 
3923
3924  this.pageDots = new PageDots( this ); 
3925  // events 
3926  this.on( 'activate', this.activatePageDots ); 
3927  this.on( 'select', this.updateSelectedPageDots ); 
3928  this.on( 'cellChange', this.updatePageDots ); 
3929  this.on( 'resize', this.updatePageDots ); 
3930  this.on( 'deactivate', this.deactivatePageDots ); 
3931}; 
3932 
3933proto.activatePageDots = function() { 
3934  this.pageDots.activate(); 
3935}; 
3936 
3937proto.updateSelectedPageDots = function() { 
3938  this.pageDots.updateSelected(); 
3939}; 
3940 
3941proto.updatePageDots = function() { 
3942  this.pageDots.setDots(); 
3943}; 
3944 
3945proto.deactivatePageDots = function() { 
3946  this.pageDots.deactivate(); 
3947}; 
3948 
3949// -----  ----- // 
3950 
3951Flickity.PageDots = PageDots; 
3952 
3953return Flickity; 
3954 
3955} ) ); 
3956 
3957// player & autoPlay 
3958( function( window, factory ) { 
3959  // universal module definition 
3960  if ( typeof define == 'function' && define.amd ) { 
3961    // AMD 
3962    define( 'flickity/js/player',[ 
3963      'ev-emitter/ev-emitter', 
3964      'fizzy-ui-utils/utils', 
3965      './flickity', 
3966    ], function( EvEmitter, utils, Flickity ) { 
3967      return factory( EvEmitter, utils, Flickity ); 
3968    } ); 
3969  } else if ( typeof module == 'object' && module.exports ) { 
3970    // CommonJS 
3971    module.exports = factory( 
3972        require('ev-emitter'), 
3973        require('fizzy-ui-utils'), 
3974        require('./flickity') 
3975    ); 
3976  } else { 
3977    // browser global 
3978    factory( 
3979        window.EvEmitter, 
3980        window.fizzyUIUtils, 
3981        window.Flickity 
3982    ); 
3983
3984 
3985}( window, function factory( EvEmitter, utils, Flickity ) { 
3986 
3987 
3988 
3989// -------------------------- Player -------------------------- // 
3990 
3991function Player( parent ) { 
3992  this.parent = parent; 
3993  this.state = 'stopped'; 
3994  // visibility change event handler 
3995  this.onVisibilityChange = this.visibilityChange.bind( this ); 
3996  this.onVisibilityPlay = this.visibilityPlay.bind( this ); 
3997
3998 
3999Player.prototype = Object.create( EvEmitter.prototype ); 
4000 
4001// start play 
4002Player.prototype.play = function() { 
4003  if ( this.state == 'playing' ) { 
4004    return; 
4005
4006  // do not play if page is hidden, start playing when page is visible 
4007  var isPageHidden = document.hidden; 
4008  if ( isPageHidden ) { 
4009    document.addEventListener( 'visibilitychange', this.onVisibilityPlay ); 
4010    return; 
4011
4012 
4013  this.state = 'playing'; 
4014  // listen to visibility change 
4015  document.addEventListener( 'visibilitychange', this.onVisibilityChange ); 
4016  // start ticking 
4017  this.tick(); 
4018}; 
4019 
4020Player.prototype.tick = function() { 
4021  // do not tick if not playing 
4022  if ( this.state != 'playing' ) { 
4023    return; 
4024
4025 
4026  var time = this.parent.options.autoPlay; 
4027  // default to 3 seconds 
4028  time = typeof time == 'number' ? time : 3000; 
4029  var _this = this; 
4030  // HACK: reset ticks if stopped and started within interval 
4031  this.clear(); 
4032  this.timeout = setTimeout( function() { 
4033    _this.parent.next( true ); 
4034    _this.tick(); 
4035  }, time ); 
4036}; 
4037 
4038Player.prototype.stop = function() { 
4039  this.state = 'stopped'; 
4040  this.clear(); 
4041  // remove visibility change event 
4042  document.removeEventListener( 'visibilitychange', this.onVisibilityChange ); 
4043}; 
4044 
4045Player.prototype.clear = function() { 
4046  clearTimeout( this.timeout ); 
4047}; 
4048 
4049Player.prototype.pause = function() { 
4050  if ( this.state == 'playing' ) { 
4051    this.state = 'paused'; 
4052    this.clear(); 
4053
4054}; 
4055 
4056Player.prototype.unpause = function() { 
4057  // re-start play if paused 
4058  if ( this.state == 'paused' ) { 
4059    this.play(); 
4060
4061}; 
4062 
4063// pause if page visibility is hidden, unpause if visible 
4064Player.prototype.visibilityChange = function() { 
4065  var isPageHidden = document.hidden; 
4066  this[ isPageHidden ? 'pause' : 'unpause' ](); 
4067}; 
4068 
4069Player.prototype.visibilityPlay = function() { 
4070  this.play(); 
4071  document.removeEventListener( 'visibilitychange', this.onVisibilityPlay ); 
4072}; 
4073 
4074// -------------------------- Flickity -------------------------- // 
4075 
4076utils.extend( Flickity.defaults, { 
4077  pauseAutoPlayOnHover: true, 
4078} ); 
4079 
4080Flickity.createMethods.push('_createPlayer'); 
4081var proto = Flickity.prototype; 
4082 
4083proto._createPlayer = function() { 
4084  this.player = new Player( this ); 
4085 
4086  this.on( 'activate', this.activatePlayer ); 
4087  this.on( 'uiChange', this.stopPlayer ); 
4088  this.on( 'pointerDown', this.stopPlayer ); 
4089  this.on( 'deactivate', this.deactivatePlayer ); 
4090}; 
4091 
4092proto.activatePlayer = function() { 
4093  if ( !this.options.autoPlay ) { 
4094    return; 
4095
4096  this.player.play(); 
4097  this.element.addEventListener( 'mouseenter', this ); 
4098}; 
4099 
4100// Player API, don't hate the ... thanks I know where the door is 
4101 
4102proto.playPlayer = function() { 
4103  this.player.play(); 
4104}; 
4105 
4106proto.stopPlayer = function() { 
4107  this.player.stop(); 
4108}; 
4109 
4110proto.pausePlayer = function() { 
4111  this.player.pause(); 
4112}; 
4113 
4114proto.unpausePlayer = function() { 
4115  this.player.unpause(); 
4116}; 
4117 
4118proto.deactivatePlayer = function() { 
4119  this.player.stop(); 
4120  this.element.removeEventListener( 'mouseenter', this ); 
4121}; 
4122 
4123// ----- mouseenter/leave ----- // 
4124 
4125// pause auto-play on hover 
4126proto.onmouseenter = function() { 
4127  if ( !this.options.pauseAutoPlayOnHover ) { 
4128    return; 
4129
4130  this.player.pause(); 
4131  this.element.addEventListener( 'mouseleave', this ); 
4132}; 
4133 
4134// resume auto-play on hover off 
4135proto.onmouseleave = function() { 
4136  this.player.unpause(); 
4137  this.element.removeEventListener( 'mouseleave', this ); 
4138}; 
4139 
4140// -----  ----- // 
4141 
4142Flickity.Player = Player; 
4143 
4144return Flickity; 
4145 
4146} ) ); 
4147 
4148// add, remove cell 
4149( function( window, factory ) { 
4150  // universal module definition 
4151  if ( typeof define == 'function' && define.amd ) { 
4152    // AMD 
4153    define( 'flickity/js/add-remove-cell',[ 
4154      './flickity', 
4155      'fizzy-ui-utils/utils', 
4156    ], function( Flickity, utils ) { 
4157      return factory( window, Flickity, utils ); 
4158    } ); 
4159  } else if ( typeof module == 'object' && module.exports ) { 
4160    // CommonJS 
4161    module.exports = factory( 
4162        window, 
4163        require('./flickity'), 
4164        require('fizzy-ui-utils') 
4165    ); 
4166  } else { 
4167    // browser global 
4168    factory( 
4169        window, 
4170        window.Flickity, 
4171        window.fizzyUIUtils 
4172    ); 
4173
4174 
4175}( window, function factory( window, Flickity, utils ) { 
4176 
4177 
4178 
4179// append cells to a document fragment 
4180function getCellsFragment( cells ) { 
4181  var fragment = document.createDocumentFragment(); 
4182  cells.forEach( function( cell ) { 
4183    fragment.appendChild( cell.element ); 
4184  } ); 
4185  return fragment; 
4186
4187 
4188// -------------------------- add/remove cell prototype -------------------------- // 
4189 
4190var proto = Flickity.prototype; 
4191 
4192/** 
4193 * Insert, prepend, or append cells 
4194 * @param {[Element, Array, NodeList]} elems - Elements to insert 
4195 * @param {Integer} index - Zero-based number to insert 
4196 */ 
4197proto.insert = function( elems, index ) { 
4198  var cells = this._makeCells( elems ); 
4199  if ( !cells || !cells.length ) { 
4200    return; 
4201
4202  var len = this.cells.length; 
4203  // default to append 
4204  index = index === undefined ? len : index; 
4205  // add cells with document fragment 
4206  var fragment = getCellsFragment( cells ); 
4207  // append to slider 
4208  var isAppend = index == len; 
4209  if ( isAppend ) { 
4210    this.slider.appendChild( fragment ); 
4211  } else { 
4212    var insertCellElement = this.cells[ index ].element; 
4213    this.slider.insertBefore( fragment, insertCellElement ); 
4214
4215  // add to this.cells 
4216  if ( index === 0 ) { 
4217    // prepend, add to start 
4218    this.cells = cells.concat( this.cells ); 
4219  } else if ( isAppend ) { 
4220    // append, add to end 
4221    this.cells = this.cells.concat( cells ); 
4222  } else { 
4223    // insert in this.cells 
4224    var endCells = this.cells.splice( index, len - index ); 
4225    this.cells = this.cells.concat( cells ).concat( endCells ); 
4226
4227 
4228  this._sizeCells( cells ); 
4229  this.cellChange( index, true ); 
4230}; 
4231 
4232proto.append = function( elems ) { 
4233  this.insert( elems, this.cells.length ); 
4234}; 
4235 
4236proto.prepend = function( elems ) { 
4237  this.insert( elems, 0 ); 
4238}; 
4239 
4240/** 
4241 * Remove cells 
4242 * @param {[Element, Array, NodeList]} elems - ELements to remove 
4243 */ 
4244proto.remove = function( elems ) { 
4245  var cells = this.getCells( elems ); 
4246  if ( !cells || !cells.length ) { 
4247    return; 
4248
4249 
4250  var minCellIndex = this.cells.length - 1; 
4251  // remove cells from collection & DOM 
4252  cells.forEach( function( cell ) { 
4253    cell.remove(); 
4254    var index = this.cells.indexOf( cell ); 
4255    minCellIndex = Math.min( index, minCellIndex ); 
4256    utils.removeFrom( this.cells, cell ); 
4257  }, this ); 
4258 
4259  this.cellChange( minCellIndex, true ); 
4260}; 
4261 
4262/** 
4263 * logic to be run after a cell's size changes 
4264 * @param {Element} elem - cell's element 
4265 */ 
4266proto.cellSizeChange = function( elem ) { 
4267  var cell = this.getCell( elem ); 
4268  if ( !cell ) { 
4269    return; 
4270
4271  cell.getSize(); 
4272 
4273  var index = this.cells.indexOf( cell ); 
4274  this.cellChange( index ); 
4275}; 
4276 
4277/** 
4278 * logic any time a cell is changed: added, removed, or size changed 
4279 * @param {Integer} changedCellIndex - index of the changed cell, optional 
4280 * @param {Boolean} isPositioningSlider - Positions slider after selection 
4281 */ 
4282proto.cellChange = function( changedCellIndex, isPositioningSlider ) { 
4283  var prevSelectedElem = this.selectedElement; 
4284  this._positionCells( changedCellIndex ); 
4285  this._getWrapShiftCells(); 
4286  this.setGallerySize(); 
4287  // update selectedIndex 
4288  // try to maintain position & select previous selected element 
4289  var cell = this.getCell( prevSelectedElem ); 
4290  if ( cell ) { 
4291    this.selectedIndex = this.getCellSlideIndex( cell ); 
4292
4293  this.selectedIndex = Math.min( this.slides.length - 1, this.selectedIndex ); 
4294 
4295  this.emitEvent( 'cellChange', [ changedCellIndex ] ); 
4296  // position slider 
4297  this.select( this.selectedIndex ); 
4298  // do not position slider after lazy load 
4299  if ( isPositioningSlider ) { 
4300    this.positionSliderAtSelected(); 
4301
4302}; 
4303 
4304// -----  ----- // 
4305 
4306return Flickity; 
4307 
4308} ) ); 
4309 
4310// lazyload 
4311( function( window, factory ) { 
4312  // universal module definition 
4313  if ( typeof define == 'function' && define.amd ) { 
4314    // AMD 
4315    define( 'flickity/js/lazyload',[ 
4316      './flickity', 
4317      'fizzy-ui-utils/utils', 
4318    ], function( Flickity, utils ) { 
4319      return factory( window, Flickity, utils ); 
4320    } ); 
4321  } else if ( typeof module == 'object' && module.exports ) { 
4322    // CommonJS 
4323    module.exports = factory( 
4324        window, 
4325        require('./flickity'), 
4326        require('fizzy-ui-utils') 
4327    ); 
4328  } else { 
4329    // browser global 
4330    factory( 
4331        window, 
4332        window.Flickity, 
4333        window.fizzyUIUtils 
4334    ); 
4335
4336 
4337}( window, function factory( window, Flickity, utils ) { 
4338'use strict'; 
4339 
4340Flickity.createMethods.push('_createLazyload'); 
4341var proto = Flickity.prototype; 
4342 
4343proto._createLazyload = function() { 
4344  this.on( 'select', this.lazyLoad ); 
4345}; 
4346 
4347proto.lazyLoad = function() { 
4348  var lazyLoad = this.options.lazyLoad; 
4349  if ( !lazyLoad ) { 
4350    return; 
4351
4352  // get adjacent cells, use lazyLoad option for adjacent count 
4353  var adjCount = typeof lazyLoad == 'number' ? lazyLoad : 0; 
4354  var cellElems = this.getAdjacentCellElements( adjCount ); 
4355  // get lazy images in those cells 
4356  var lazyImages = []; 
4357  cellElems.forEach( function( cellElem ) { 
4358    var lazyCellImages = getCellLazyImages( cellElem ); 
4359    lazyImages = lazyImages.concat( lazyCellImages ); 
4360  } ); 
4361  // load lazy images 
4362  lazyImages.forEach( function( img ) { 
4363    new LazyLoader( img, this ); 
4364  }, this ); 
4365}; 
4366 
4367function getCellLazyImages( cellElem ) { 
4368  // check if cell element is lazy image 
4369  if ( cellElem.nodeName == 'IMG' ) { 
4370    var lazyloadAttr = cellElem.getAttribute('data-flickity-lazyload'); 
4371    var srcAttr = cellElem.getAttribute('data-flickity-lazyload-src'); 
4372    var srcsetAttr = cellElem.getAttribute('data-flickity-lazyload-srcset'); 
4373    if ( lazyloadAttr || srcAttr || srcsetAttr ) { 
4374      return [ cellElem ]; 
4375
4376
4377  // select lazy images in cell 
4378  var lazySelector = 'img[data-flickity-lazyload], ' + 
4379    'img[data-flickity-lazyload-src], img[data-flickity-lazyload-srcset]'; 
4380  var imgs = cellElem.querySelectorAll( lazySelector ); 
4381  return utils.makeArray( imgs ); 
4382
4383 
4384// -------------------------- LazyLoader -------------------------- // 
4385 
4386/** 
4387 * class to handle loading images 
4388 * @param {Image} img - Image element 
4389 * @param {Flickity} flickity - Flickity instance 
4390 */ 
4391function LazyLoader( img, flickity ) { 
4392  this.img = img; 
4393  this.flickity = flickity; 
4394  this.load(); 
4395
4396 
4397LazyLoader.prototype.handleEvent = utils.handleEvent; 
4398 
4399LazyLoader.prototype.load = function() { 
4400  this.img.addEventListener( 'load', this ); 
4401  this.img.addEventListener( 'error', this ); 
4402  // get src & srcset 
4403  var src = this.img.getAttribute('data-flickity-lazyload') || 
4404    this.img.getAttribute('data-flickity-lazyload-src'); 
4405  var srcset = this.img.getAttribute('data-flickity-lazyload-srcset'); 
4406  // set src & serset 
4407  this.img.src = src; 
4408  if ( srcset ) { 
4409    this.img.setAttribute( 'srcset', srcset ); 
4410
4411  // remove attr 
4412  this.img.removeAttribute('data-flickity-lazyload'); 
4413  this.img.removeAttribute('data-flickity-lazyload-src'); 
4414  this.img.removeAttribute('data-flickity-lazyload-srcset'); 
4415}; 
4416 
4417LazyLoader.prototype.onload = function( event ) { 
4418  this.complete( event, 'flickity-lazyloaded' ); 
4419}; 
4420 
4421LazyLoader.prototype.onerror = function( event ) { 
4422  this.complete( event, 'flickity-lazyerror' ); 
4423}; 
4424 
4425LazyLoader.prototype.complete = function( event, className ) { 
4426  // unbind events 
4427  this.img.removeEventListener( 'load', this ); 
4428  this.img.removeEventListener( 'error', this ); 
4429 
4430  var cell = this.flickity.getParentCell( this.img ); 
4431  var cellElem = cell && cell.element; 
4432  this.flickity.cellSizeChange( cellElem ); 
4433 
4434  this.img.classList.add( className ); 
4435  this.flickity.dispatchEvent( 'lazyLoad', event, cellElem ); 
4436}; 
4437 
4438// -----  ----- // 
4439 
4440Flickity.LazyLoader = LazyLoader; 
4441 
4442return Flickity; 
4443 
4444} ) ); 
4445 
4446/*! 
4447 * Flickity v2.2.2 
4448 * Touch, responsive, flickable carousels 
4449
4450 * Licensed GPLv3 for open source use 
4451 * or Flickity Commercial License for commercial use 
4452
4453 * https://flickity.metafizzy.co 
4454 * Copyright 2015-2021 Metafizzy 
4455 */ 
4456 
4457( function( window, factory ) { 
4458  // universal module definition 
4459  if ( typeof define == 'function' && define.amd ) { 
4460    // AMD 
4461    define( 'flickity/js/index',[ 
4462      './flickity', 
4463      './drag', 
4464      './prev-next-button', 
4465      './page-dots', 
4466      './player', 
4467      './add-remove-cell', 
4468      './lazyload', 
4469    ], factory ); 
4470  } else if ( typeof module == 'object' && module.exports ) { 
4471    // CommonJS 
4472    module.exports = factory( 
4473        require('./flickity'), 
4474        require('./drag'), 
4475        require('./prev-next-button'), 
4476        require('./page-dots'), 
4477        require('./player'), 
4478        require('./add-remove-cell'), 
4479        require('./lazyload') 
4480    ); 
4481
4482 
4483} )( window, function factory( Flickity ) { 
4484  return Flickity; 
4485} ); 
4486 
4487/*! 
4488 * Flickity asNavFor v2.0.2 
4489 * enable asNavFor for Flickity 
4490 */ 
4491 
4492/*jshint browser: true, undef: true, unused: true, strict: true*/ 
4493 
4494( function( window, factory ) { 
4495  // universal module definition 
4496  /*jshint strict: false */ /*globals define, module, require */ 
4497  if ( typeof define == 'function' && define.amd ) { 
4498    // AMD 
4499    define( 'flickity-as-nav-for/as-nav-for',[ 
4500      'flickity/js/index', 
4501      'fizzy-ui-utils/utils' 
4502    ], factory ); 
4503  } else if ( typeof module == 'object' && module.exports ) { 
4504    // CommonJS 
4505    module.exports = factory( 
4506      require('flickity'), 
4507      require('fizzy-ui-utils') 
4508    ); 
4509  } else { 
4510    // browser global 
4511    window.Flickity = factory( 
4512      window.Flickity, 
4513      window.fizzyUIUtils 
4514    ); 
4515
4516 
4517}( window, function factory( Flickity, utils ) { 
4518 
4519 
4520 
4521// -------------------------- asNavFor prototype -------------------------- // 
4522 
4523// Flickity.defaults.asNavFor = null; 
4524 
4525Flickity.createMethods.push('_createAsNavFor'); 
4526 
4527var proto = Flickity.prototype; 
4528 
4529proto._createAsNavFor = function() { 
4530  this.on( 'activate', this.activateAsNavFor ); 
4531  this.on( 'deactivate', this.deactivateAsNavFor ); 
4532  this.on( 'destroy', this.destroyAsNavFor ); 
4533 
4534  var asNavForOption = this.options.asNavFor; 
4535  if ( !asNavForOption ) { 
4536    return; 
4537
4538  // HACK do async, give time for other flickity to be initalized 
4539  var _this = this; 
4540  setTimeout( function initNavCompanion() { 
4541    _this.setNavCompanion( asNavForOption ); 
4542  }); 
4543}; 
4544 
4545proto.setNavCompanion = function( elem ) { 
4546  elem = utils.getQueryElement( elem ); 
4547  var companion = Flickity.data( elem ); 
4548  // stop if no companion or companion is self 
4549  if ( !companion || companion == this ) { 
4550    return; 
4551
4552 
4553  this.navCompanion = companion; 
4554  // companion select 
4555  var _this = this; 
4556  this.onNavCompanionSelect = function() { 
4557    _this.navCompanionSelect(); 
4558  }; 
4559  companion.on( 'select', this.onNavCompanionSelect ); 
4560  // click 
4561  this.on( 'staticClick', this.onNavStaticClick ); 
4562 
4563  this.navCompanionSelect( true ); 
4564}; 
4565 
4566proto.navCompanionSelect = function( isInstant ) { 
4567  // wait for companion & selectedCells first. #8 
4568  var companionCells = this.navCompanion && this.navCompanion.selectedCells; 
4569  if ( !companionCells ) { 
4570    return; 
4571
4572  // select slide that matches first cell of slide 
4573  var selectedCell = companionCells[0]; 
4574  var firstIndex = this.navCompanion.cells.indexOf( selectedCell ); 
4575  var lastIndex = firstIndex + companionCells.length - 1; 
4576  var selectIndex = Math.floor( lerp( firstIndex, lastIndex, 
4577    this.navCompanion.cellAlign ) ); 
4578  this.selectCell( selectIndex, false, isInstant ); 
4579  // set nav selected class 
4580  this.removeNavSelectedElements(); 
4581  // stop if companion has more cells than this one 
4582  if ( selectIndex >= this.cells.length ) { 
4583    return; 
4584
4585 
4586  var selectedCells = this.cells.slice( firstIndex, lastIndex + 1 ); 
4587  this.navSelectedElements = selectedCells.map( function( cell ) { 
4588    return cell.element; 
4589  }); 
4590  this.changeNavSelectedClass('add'); 
4591}; 
4592 
4593function lerp( a, b, t ) { 
4594  return ( b - a ) * t + a; 
4595
4596 
4597proto.changeNavSelectedClass = function( method ) { 
4598  this.navSelectedElements.forEach( function( navElem ) { 
4599    navElem.classList[ method ]('is-nav-selected'); 
4600  }); 
4601}; 
4602 
4603proto.activateAsNavFor = function() { 
4604  this.navCompanionSelect( true ); 
4605}; 
4606 
4607proto.removeNavSelectedElements = function() { 
4608  if ( !this.navSelectedElements ) { 
4609    return; 
4610
4611  this.changeNavSelectedClass('remove'); 
4612  delete this.navSelectedElements; 
4613}; 
4614 
4615proto.onNavStaticClick = function( event, pointer, cellElement, cellIndex ) { 
4616  if ( typeof cellIndex == 'number' ) { 
4617    this.navCompanion.selectCell( cellIndex ); 
4618
4619}; 
4620 
4621proto.deactivateAsNavFor = function() { 
4622  this.removeNavSelectedElements(); 
4623}; 
4624 
4625proto.destroyAsNavFor = function() { 
4626  if ( !this.navCompanion ) { 
4627    return; 
4628
4629  this.navCompanion.off( 'select', this.onNavCompanionSelect ); 
4630  this.off( 'staticClick', this.onNavStaticClick ); 
4631  delete this.navCompanion; 
4632}; 
4633 
4634// -----  ----- // 
4635 
4636return Flickity; 
4637 
4638})); 
4639 
4640/*! 
4641 * imagesLoaded v4.1.4 
4642 * JavaScript is all like "You images are done yet or what?" 
4643 * MIT License 
4644 */ 
4645 
4646( function( window, factory ) { 'use strict'; 
4647  // universal module definition 
4648 
4649  /*global define: false, module: false, require: false */ 
4650 
4651  if ( typeof define == 'function' && define.amd ) { 
4652    // AMD 
4653    define( 'imagesloaded/imagesloaded',[ 
4654      'ev-emitter/ev-emitter' 
4655    ], function( EvEmitter ) { 
4656      return factory( window, EvEmitter ); 
4657    }); 
4658  } else if ( typeof module == 'object' && module.exports ) { 
4659    // CommonJS 
4660    module.exports = factory( 
4661      window, 
4662      require('ev-emitter') 
4663    ); 
4664  } else { 
4665    // browser global 
4666    window.imagesLoaded = factory( 
4667      window, 
4668      window.EvEmitter 
4669    ); 
4670
4671 
4672})( typeof window !== 'undefined' ? window : this, 
4673 
4674// --------------------------  factory -------------------------- // 
4675 
4676function factory( window, EvEmitter ) { 
4677 
4678 
4679 
4680var $ = window.jQuery; 
4681var console = window.console; 
4682 
4683// -------------------------- helpers -------------------------- // 
4684 
4685// extend objects 
4686function extend( a, b ) { 
4687  for ( var prop in b ) { 
4688    a[ prop ] = b[ prop ]; 
4689
4690  return a; 
4691
4692 
4693var arraySlice = Array.prototype.slice; 
4694 
4695// turn element or nodeList into an array 
4696function makeArray( obj ) { 
4697  if ( Array.isArray( obj ) ) { 
4698    // use object if already an array 
4699    return obj; 
4700
4701 
4702  var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; 
4703  if ( isArrayLike ) { 
4704    // convert nodeList to array 
4705    return arraySlice.call( obj ); 
4706
4707 
4708  // array of single index 
4709  return [ obj ]; 
4710
4711 
4712// -------------------------- imagesLoaded -------------------------- // 
4713 
4714/** 
4715 * @param {Array, Element, NodeList, String} elem 
4716 * @param {Object or Function} options - if function, use as callback 
4717 * @param {Function} onAlways - callback function 
4718 */ 
4719function ImagesLoaded( elem, options, onAlways ) { 
4720  // coerce ImagesLoaded() without new, to be new ImagesLoaded() 
4721  if ( !( this instanceof ImagesLoaded ) ) { 
4722    return new ImagesLoaded( elem, options, onAlways ); 
4723
4724  // use elem as selector string 
4725  var queryElem = elem; 
4726  if ( typeof elem == 'string' ) { 
4727    queryElem = document.querySelectorAll( elem ); 
4728
4729  // bail if bad element 
4730  if ( !queryElem ) { 
4731    console.error( 'Bad element for imagesLoaded ' + ( queryElem || elem ) ); 
4732    return; 
4733
4734 
4735  this.elements = makeArray( queryElem ); 
4736  this.options = extend( {}, this.options ); 
4737  // shift arguments if no options set 
4738  if ( typeof options == 'function' ) { 
4739    onAlways = options; 
4740  } else { 
4741    extend( this.options, options ); 
4742
4743 
4744  if ( onAlways ) { 
4745    this.on( 'always', onAlways ); 
4746
4747 
4748  this.getImages(); 
4749 
4750  if ( $ ) { 
4751    // add jQuery Deferred object 
4752    this.jqDeferred = new $.Deferred(); 
4753
4754 
4755  // HACK check async to allow time to bind listeners 
4756  setTimeout( this.check.bind( this ) ); 
4757
4758 
4759ImagesLoaded.prototype = Object.create( EvEmitter.prototype ); 
4760 
4761ImagesLoaded.prototype.options = {}; 
4762 
4763ImagesLoaded.prototype.getImages = function() { 
4764  this.images = []; 
4765 
4766  // filter & find items if we have an item selector 
4767  this.elements.forEach( this.addElementImages, this ); 
4768}; 
4769 
4770/** 
4771 * @param {Node} element 
4772 */ 
4773ImagesLoaded.prototype.addElementImages = function( elem ) { 
4774  // filter siblings 
4775  if ( elem.nodeName == 'IMG' ) { 
4776    this.addImage( elem ); 
4777
4778  // get background image on element 
4779  if ( this.options.background === true ) { 
4780    this.addElementBackgroundImages( elem ); 
4781
4782 
4783  // find children 
4784  // no non-element nodes, #143 
4785  var nodeType = elem.nodeType; 
4786  if ( !nodeType || !elementNodeTypes[ nodeType ] ) { 
4787    return; 
4788
4789  var childImgs = elem.querySelectorAll('img'); 
4790  // concat childElems to filterFound array 
4791  for ( var i=0; i < childImgs.length; i++ ) { 
4792    var img = childImgs[i]; 
4793    this.addImage( img ); 
4794
4795 
4796  // get child background images 
4797  if ( typeof this.options.background == 'string' ) { 
4798    var children = elem.querySelectorAll( this.options.background ); 
4799    for ( i=0; i < children.length; i++ ) { 
4800      var child = children[i]; 
4801      this.addElementBackgroundImages( child ); 
4802
4803
4804}; 
4805 
4806var elementNodeTypes = { 
4807  1: true, 
4808  9: true, 
4809  11: true 
4810}; 
4811 
4812ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) { 
4813  var style = getComputedStyle( elem ); 
4814  if ( !style ) { 
4815    // Firefox returns null if in a hidden iframe https://bugzil.la/548397 
4816    return; 
4817
4818  // get url inside url("...") 
4819  var reURL = /url\((['"])?(.*?)\1\)/gi; 
4820  var matches = reURL.exec( style.backgroundImage ); 
4821  while ( matches !== null ) { 
4822    var url = matches && matches[2]; 
4823    if ( url ) { 
4824      this.addBackground( url, elem ); 
4825
4826    matches = reURL.exec( style.backgroundImage ); 
4827
4828}; 
4829 
4830/** 
4831 * @param {Image} img 
4832 */ 
4833ImagesLoaded.prototype.addImage = function( img ) { 
4834  var loadingImage = new LoadingImage( img ); 
4835  this.images.push( loadingImage ); 
4836}; 
4837 
4838ImagesLoaded.prototype.addBackground = function( url, elem ) { 
4839  var background = new Background( url, elem ); 
4840  this.images.push( background ); 
4841}; 
4842 
4843ImagesLoaded.prototype.check = function() { 
4844  var _this = this; 
4845  this.progressedCount = 0; 
4846  this.hasAnyBroken = false; 
4847  // complete if no images 
4848  if ( !this.images.length ) { 
4849    this.complete(); 
4850    return; 
4851
4852 
4853  function onProgress( image, elem, message ) { 
4854    // HACK - Chrome triggers event before object properties have changed. #83 
4855    setTimeout( function() { 
4856      _this.progress( image, elem, message ); 
4857    }); 
4858
4859 
4860  this.images.forEach( function( loadingImage ) { 
4861    loadingImage.once( 'progress', onProgress ); 
4862    loadingImage.check(); 
4863  }); 
4864}; 
4865 
4866ImagesLoaded.prototype.progress = function( image, elem, message ) { 
4867  this.progressedCount++; 
4868  this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded; 
4869  // progress event 
4870  this.emitEvent( 'progress', [ this, image, elem ] ); 
4871  if ( this.jqDeferred && this.jqDeferred.notify ) { 
4872    this.jqDeferred.notify( this, image ); 
4873
4874  // check if completed 
4875  if ( this.progressedCount == this.images.length ) { 
4876    this.complete(); 
4877
4878 
4879  if ( this.options.debug && console ) { 
4880    console.log( 'progress: ' + message, image, elem ); 
4881
4882}; 
4883 
4884ImagesLoaded.prototype.complete = function() { 
4885  var eventName = this.hasAnyBroken ? 'fail' : 'done'; 
4886  this.isComplete = true; 
4887  this.emitEvent( eventName, [ this ] ); 
4888  this.emitEvent( 'always', [ this ] ); 
4889  if ( this.jqDeferred ) { 
4890    var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve'; 
4891    this.jqDeferred[ jqMethod ]( this ); 
4892
4893}; 
4894 
4895// --------------------------  -------------------------- // 
4896 
4897function LoadingImage( img ) { 
4898  this.img = img; 
4899
4900 
4901LoadingImage.prototype = Object.create( EvEmitter.prototype ); 
4902 
4903LoadingImage.prototype.check = function() { 
4904  // If complete is true and browser supports natural sizes, 
4905  // try to check for image status manually. 
4906  var isComplete = this.getIsImageComplete(); 
4907  if ( isComplete ) { 
4908    // report based on naturalWidth 
4909    this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 
4910    return; 
4911
4912 
4913  // If none of the checks above matched, simulate loading on detached element. 
4914  this.proxyImage = new Image(); 
4915  this.proxyImage.addEventListener( 'load', this ); 
4916  this.proxyImage.addEventListener( 'error', this ); 
4917  // bind to image as well for Firefox. #191 
4918  this.img.addEventListener( 'load', this ); 
4919  this.img.addEventListener( 'error', this ); 
4920  this.proxyImage.src = this.img.src; 
4921}; 
4922 
4923LoadingImage.prototype.getIsImageComplete = function() { 
4924  // check for non-zero, non-undefined naturalWidth 
4925  // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671 
4926  return this.img.complete && this.img.naturalWidth; 
4927}; 
4928 
4929LoadingImage.prototype.confirm = function( isLoaded, message ) { 
4930  this.isLoaded = isLoaded; 
4931  this.emitEvent( 'progress', [ this, this.img, message ] ); 
4932}; 
4933 
4934// ----- events ----- // 
4935 
4936// trigger specified handler for event type 
4937LoadingImage.prototype.handleEvent = function( event ) { 
4938  var method = 'on' + event.type; 
4939  if ( this[ method ] ) { 
4940    this[ method ]( event ); 
4941
4942}; 
4943 
4944LoadingImage.prototype.onload = function() { 
4945  this.confirm( true, 'onload' ); 
4946  this.unbindEvents(); 
4947}; 
4948 
4949LoadingImage.prototype.onerror = function() { 
4950  this.confirm( false, 'onerror' ); 
4951  this.unbindEvents(); 
4952}; 
4953 
4954LoadingImage.prototype.unbindEvents = function() { 
4955  this.proxyImage.removeEventListener( 'load', this ); 
4956  this.proxyImage.removeEventListener( 'error', this ); 
4957  this.img.removeEventListener( 'load', this ); 
4958  this.img.removeEventListener( 'error', this ); 
4959}; 
4960 
4961// -------------------------- Background -------------------------- // 
4962 
4963function Background( url, element ) { 
4964  this.url = url; 
4965  this.element = element; 
4966  this.img = new Image(); 
4967
4968 
4969// inherit LoadingImage prototype 
4970Background.prototype = Object.create( LoadingImage.prototype ); 
4971 
4972Background.prototype.check = function() { 
4973  this.img.addEventListener( 'load', this ); 
4974  this.img.addEventListener( 'error', this ); 
4975  this.img.src = this.url; 
4976  // check if image is already complete 
4977  var isComplete = this.getIsImageComplete(); 
4978  if ( isComplete ) { 
4979    this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' ); 
4980    this.unbindEvents(); 
4981
4982}; 
4983 
4984Background.prototype.unbindEvents = function() { 
4985  this.img.removeEventListener( 'load', this ); 
4986  this.img.removeEventListener( 'error', this ); 
4987}; 
4988 
4989Background.prototype.confirm = function( isLoaded, message ) { 
4990  this.isLoaded = isLoaded; 
4991  this.emitEvent( 'progress', [ this, this.element, message ] ); 
4992}; 
4993 
4994// -------------------------- jQuery -------------------------- // 
4995 
4996ImagesLoaded.makeJQueryPlugin = function( jQuery ) { 
4997  jQuery = jQuery || window.jQuery; 
4998  if ( !jQuery ) { 
4999    return; 
5000
5001  // set local variable 
5002  $ = jQuery; 
5003  // $().imagesLoaded() 
5004  $.fn.imagesLoaded = function( options, callback ) { 
5005    var instance = new ImagesLoaded( this, options, callback ); 
5006    return instance.jqDeferred.promise( $(this) ); 
5007  }; 
5008}; 
5009// try making plugin 
5010ImagesLoaded.makeJQueryPlugin(); 
5011 
5012// --------------------------  -------------------------- // 
5013 
5014return ImagesLoaded; 
5015 
5016}); 
5017 
5018/*! 
5019 * Flickity imagesLoaded v2.0.0 
5020 * enables imagesLoaded option for Flickity 
5021 */ 
5022 
5023/*jshint browser: true, strict: true, undef: true, unused: true */ 
5024 
5025( function( window, factory ) { 
5026  // universal module definition 
5027  /*jshint strict: false */ /*globals define, module, require */ 
5028  if ( typeof define == 'function' && define.amd ) { 
5029    // AMD 
5030    define( [ 
5031      'flickity/js/index', 
5032      'imagesloaded/imagesloaded' 
5033    ], function( Flickity, imagesLoaded ) { 
5034      return factory( window, Flickity, imagesLoaded ); 
5035    }); 
5036  } else if ( typeof module == 'object' && module.exports ) { 
5037    // CommonJS 
5038    module.exports = factory( 
5039      window, 
5040      require('flickity'), 
5041      require('imagesloaded') 
5042    ); 
5043  } else { 
5044    // browser global 
5045    window.Flickity = factory( 
5046      window, 
5047      window.Flickity, 
5048      window.imagesLoaded 
5049    ); 
5050
5051 
5052}( window, function factory( window, Flickity, imagesLoaded ) { 
5053'use strict'; 
5054 
5055Flickity.createMethods.push('_createImagesLoaded'); 
5056 
5057var proto = Flickity.prototype; 
5058 
5059proto._createImagesLoaded = function() { 
5060  this.on( 'activate', this.imagesLoaded ); 
5061}; 
5062 
5063proto.imagesLoaded = function() { 
5064  if ( !this.options.imagesLoaded ) { 
5065    return; 
5066
5067  var _this = this; 
5068  function onImagesLoadedProgress( instance, image ) { 
5069    var cell = _this.getParentCell( image.img ); 
5070    _this.cellSizeChange( cell && cell.element ); 
5071    if ( !_this.options.freeScroll ) { 
5072      _this.positionSliderAtSelected(); 
5073
5074
5075  imagesLoaded( this.slider ).on( 'progress', onImagesLoadedProgress ); 
5076}; 
5077 
5078return Flickity; 
5079 
5080})); 
5081 
5082</script> 
5083<script> 
5084$(function(){ 
5085 
5086     $('a[href*=#]').click(function() { 
5087 
5088     if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') 
5089         && location.hostname == this.hostname) { 
5090 
5091             var $target = $(this.hash); 
5092 
5093             $target = $target.length && $target || $('[name=' + this.hash.slice(1) +']'); 
5094 
5095             if ($target.length) { 
5096 
5097                 var targetOffset = $target.offset().top; 
5098 
5099                 $('html,body').animate({scrollTop: targetOffset}, 800); 
5100 
5101                 return false; 
5102 
5103
5104 
5105
5106 
5107   }); 
5108 
5109}); 
5110</script>