• LEE tu colegio
  • Publicaciones y documentos
  • Iniciativas
  • Noticias
  • Datos y estadísticas
  • Nosotros
  • Contacto

 

Publicaciones y documentos - LEE

 

Publicaciones y documentos

 

Socializamos nuestros hallazgos, análisis y propuestas sobre aspectos de la educación en Colombia y sus desafíos.

  • 2025
  • 2024
  • 2023
  • 2022
  • 2021
  • 2020
  • Informe 132: La voz de los docentes en perspectiva internacional: resultados de TALIS 2024 en Colombia (Nov 2025) 
  • Informe 131: De Colciencias a Ministerio de Ciencia, Tecnología e Innovación:  análisis a la gestión y resultados (Nov 2025) 
  • Informe 130: Voces de las niñas y adolescentes en cifras: estadísticas de embarazo temprano en Colombia (Octubre 2025) 
  • Informe 129: Panorama nacional del desarrollo socioemocional: evidencias para fortalecer la salud mental en el sistema educativo. (Octubre 2025) 
  • Informe 128: Diversidad de muestras, diversidad de resultados: lecciones internacionales desde PISA (Sept 2025) 
  • Informe 127: Formación de alto nivel en Colombia (Sept 2025) 
  • Informe 126: Así eligen los jóvenes en Colombia: radiografía de las carreras más demandadas (Sept 2025) 
  • Informe 125: Competencias juveniles en Colombia: análisis de habilidades generales y digitales a partir de registros del SPE (Agosto 2025) 
  • Informe 124: Financiación de la educación superior: realidades y retos para el sector (Agosto 2025) 
  • Informe 123: Estadísticas en educación superior en pregrado en Colombia (Agosto 2025) 
  • Informe 122: Régimen de seguridad social en la carrera docente en Colombia (Julio 2025) 
  • Informe 121: Entre pantallas y aprendizajes: Uso de dispositivos digitales en Colombia según PISA 2022 (Julio 2025) 
  • Informe 120: El lento camino de Jornada Única en Colombia: estadísticas a 2023 (Julio 2025) 
  • Informe 119: Análisis del trabajo infantil en Colombia (Junio 2025) 
  • Informe 118: Educación Interrumpida: Dinámicas y Desafíos de la Inasistencia Escolar en Colombia (Mayo 2025) 
  • Informe 117: Análisis de Brechas educativas en la población Afrocolombiana (Mayo 2025) 
  • Informe 116: Desigualdades que se leen: análisis territorial y socioeconómico de los hábitos de lectura en Colombia (Abril 2025) 
  • Informe 115: Alertas Tempranas y Educación en Colombia: Diagnóstico de la afectación del conflicto en las comunidades educativas (Abril 2025) 
  • Informe 114: Pruebas Saber 11: cerrando brechas de sector, más no de género y de zona (Marzo 2025) 
  • Informe 113: Tecnologías de la información en las aulas colombianas: usos y oportunidades (Marzo 2025) 
  • Informe 112: Espacios que Educan: Desafíos en la Infraestructura de la Educación (Febrero 2025) 
  • Informe 111: Avances y desafíos: el papel de la mujer y la niña en la Ciencia y las Matemáticas (Febrero 2025) 
  • Informe 110: La educación colombiana: hitos y retos (Diciembre 2024) 
  • Informe 109: Reporte Índice Welbin 2024: condiciones y prácticas escolares para el bienestar (Noviembre 2024) 
  • Informe 108: La situación de los estudiantes venezolanos en el sistema educativo colombiano (Noviembre 2024) 
  • Informe 107: Primera infancia en Colombia: cifras y contexto (Octubre 2024) 
  • Informe 106: Cerrando puertas: la realidad del cierre de colegios en Colombia (Octubre 2024) 
  • Informe 105: Radiografía de la educación regular en Colombia (preescolar, básica y media) (Septiembre 2024)
  • Informe 104: Tendencias ocupacionales 2023 (Septiembre 2024)
  • Informe 103: Educación Superior en Colombia – parte I (Agosto 2024)
  • Informe 102: La etnoeducación en Colombia 1994-2024: una forma de visibilizar y fortalecer las identidades culturales de los grupos étnicos (Agosto 2024)
  • Informe 101: Comportamiento del Índice de Costos de la Educación Superior (ICES) – Primer Semestre de 2024 (Agosto 2024)
  • Informe 100: ¡Cien informes desde el nacimiento del LEE de la Javeriana! (Reservado para un informe especial, espéralo pronto)
  • Informe 99: Sin Trabajo ni Educación: El Desafío de los Ninis y su Repercusión en el Futuro de la Sociedad (2023) (Julio 2024)
  • Informe 98: Calidad Educativa en Zonas Rurales de Colombia: Un Camino por Recorrer (Julio 2024)
  • Informe 97: Consumo de tabaco y cigarrillo electrónico en bachillerato 2022 (Junio 2024)
  • Informe 96: Diversidad y dinámica docente: un análisis a través de la Prueba PISA 2022 (Mayo 2024)
  • Informe 95: Reflexiones sobre el proyecto de Ley Estatutaria de Educación de Colombia (Mayo 2024)
  • Informe 94: El acoso escolar en los colegios colombianos: un análisis desde las pruebas PISA y el SUICE (Mayo 2024)
  • Informe 93: Día Internacional del Libro: bajos hábitos de lectura en Colombia (Abril 2024)
  • Informe 92: Pruebas Saber 11: una década de análisis (Abril 2024)
  • Informe 91: Análisis detallado del Programa de Alimentación Escolar (PAE) en Colombia, desde la evidencia (Abril 2024)
  • Informe 90: Índice de Costos de la Educación Superior (ICES) en Colombia y su rol en el financiamiento de la educación superior (Abril 2024)
  • Informe 89: A propósito del Día Internacional de las Matemáticas: resultados de estudiantes colombianos (Marzo 2024)
  • Informe 88: Conmemoración del 8M: Colombianas, cuidadoras y trabajadoras domésticas (Marzo 2024)
  • Informe 87: Tras las huellas del conflicto en Colombia: impacto en el rendimiento educativo (2015-2022)(Feb. 2024)
  • Informe 86: El rol crucial de la Niña y la Mujer en la Ciencia (Feb. 2024)
  • Informe 85: La educación ambiental en Colombia (Enero 2024)
  • Informe 84: Colombia y el mundo: bajos resultados en las Pruebas PISA 2022(Dic 2023)
  • Informe 83: Sistema mixto de la educación superior: Importancia y funcionamiento en Colombia (Dic 2023)
  • Informe 82: Docentes y calidad educativa: una mirada en su relación desde las pruebas Saber 11 (Nov 2023)
  • Informe 81: La ruta hacia el bienestar escolar Índice Welbin Colombia, 2023 (Oct 2023)
  • Informe 80: Panorama de la educación: fichas regionales (Oct 2023)
  • Informe 79: Características y retos de la educación rural en Colombia (Octubre 2023)
  • Informe 78: Suicidio entre los jóvenes colombianos - Día Mundial de Prevención del Suicidio (Septiembre 2023)
  • Informe 77: Cobertura y matrícula en educación superior: Cifras para Colombia  (Agosto 2023)
  • Informe 76: Cobertura del ICETEX en pregrado y posgrado (Julio 2023)
  • Informe 75: Cifras de educación superior en Colombia: inscritos, admitidos y matriculados a primer curso (Julio 2023)
  • Informe 74: Deserción en la educación superior en Colombia (Junio 2023)
  • Informe 73: Tasas de eficiencia educativa en Colombia: cobertura, matrícula, aprobación, reprobación y deserción (Mayo 2023)
  • Informe 72: ACOSO ESCOLAR EN COLEGIOS ¿Qué es y qué hacer ante el acoso? (Mayo 2023)
  • Informe 71: Acceso a bibliotecas y lectura fuera de la jornada escolar (Abril. 2023)
  • Informe 70: Evolución del desempeño en Saber 11: ¿Qué pasó en Colombia en el 2022? (Abril. 2023)
  • Informe 69: Inglés, el factor de competitividad pendiente en Colombia (Mar. 2023)
  • Informe 68: Consumo de tabaco en jóvenes y adolescentes en Colombia (Feb. 2023)
  • Informe 67: Las mujeres son minoría en las carreras STEM (Feb. 2023)
  • Informe 66: Búsqueda de cupos escolares: el drama de las familias colombianas (Nov. 2022)
  • Informe 65: Embarazo infantil y adolescente en Colombia (Noviembre 2022)
  • Informe 64: Primeros resultados de “Evaluar para avanzar”: la nueva estrategia del ICFES (Oct. 2022)
  • Informe 63: Gestión del riesgo en instituciones educativas en Colombia (Sep. 2022)
  • Informe 62: Condiciones escolares para el bienestar. Índice Welbin, Colombia 2022 (Sep. 2022)
  • Informe 61: Educación para el trabajo y desarrollo humano (ETDH), la opción de muchos colombianos para continuar sus estudios (Sep. 2022)
  • Informe 60: Ninis: la realidad de los jóvenes colombianos (Agosto 2022)
  • Informe 59: Inversión en Investigación y Desarrollo (I+D): evidencia a través de las patentes (Agosto 2022)
  • Informe 58: Evolución de la Matrícula de Educación Superior en Colombia (Agosto 2022)
  • Informe 57: Conflicto armado en niños, niñas y adolescentes en Colombia (Agosto 2022)
  • Informe 56: Inasistencia a establecimientos educativos en Colombia antes y durante la pandemia: cifras y razones (Julio 2022)
  • Informe 55: Docentes de educación básica y media en provisionalidad en Colombia (Junio 2022)
  • Informe 54: El bullying escolar en Colombia: informe comparativo con otros países de la región (Mayo 2022)
  • Informe 53: Evolución de la jornada única en Colombia (Abril 2022)
  • Informe 52: ¿Qué sucedió con la repitencia escolar al inicio de la pandemia? (Marzo 2022)
  • Informe 51: Delitos sexuales a menores en Colombia y sus efectos: la educación sexual como principal herramienta para prevenirlos (Marzo 2022)
  • Informe 50: A propósito del 8M: mujeres colombianas, con más años de educación, pero con desventajas históricas en el mundo laboral (Marzo 2022)
  • Informe 49: Brechas territoriales en resultados de Pruebas Saber 11: Regiones y departamentos antes y durante la pandemia por Covid-19 (Febrero 2022)
  • Informe 48:  Informe territorial pruebas Saber 11 – Aplicativo Excel (Febrero 2022)
  • Informe 47:  LEE TU COLEGIO Índice Multidimensional de Colegios Oficiales de Colombia y sus resultados 2020 (Febrero 2022)
  • Informe 46:  Brechas en resultados de Pruebas Saber 11: Colombia antes y durante la pandemia por covid-19 (Febrero 2022)
  • Informe 45: Evolución de la planta docente en Colombia en tiempos de pandemia (Octubre 2021)
  • Informe 44: Alimentación escolar en tiempos de pandemia (Octubre 2021)
  • Informe 43: Desafíos y brechas en cobertura en primera infancia en Colombia (Octubre 2021)
  • Informe 42: Matrícula de Educación Superior en Colombia en Pandemia (Septiembre 2021)
  • Informe 41: Migración de estudiantes a principales ciudades de Colombia en tránsito inmediato a educación superior (Septiembre 2021)
  • Informe 40: Tránsito Inmediato a Educación Superior (Agosto 2021)
  • Informe 39: ¿Están adquiriendo los estudiantes de pregrado en Colombia las competencias que exige su profesión? Saber Pro 2019 – Análisis de resultados en competencias específicas (Agosto 2021)
  • Informe 38: Innovaciones en educación para recuperar las brechas de aprendizaje ampliadas por la pandemia del COVID-19 (Julio 2021)
  • Informe 37: Educación en los centros de reclusión para adultos, un desafío para la reincorporación social en el país (Julio 2021)
  • Informe 36: Traslado de estudiantes al sector oficial en un contexto de pandemia (Junio 2021)
  • Informe 35: Trabajo infantil durante la pandemia del COVID-19 (Junio 2021)
  • Informe 34: Colegios saludables y su relación con el desempeño académico. (Junio 2021)
  • Informe 33: Estrategias de financiación a la demanda en educación superior en Colombia: Tú Eliges, Ser Pilo Paga y Generación E. (Mayo 2021)
  • Informe 32: Satisfacción laboral y motivación de los docentes en Colombia – Día del Maestro 2021 (Mayo 2021)
  • Informe 31: Retos en las capacidades de comprensión lectora en Colombia (Abril 2021)
  • Informe 30: La brecha de género en investigación en Colombia (Marzo 2021)
  • Informe 29: Servicio de agua en instituciones educativas (Febrero 2021)
  • Informe 28: Grandes retos para la educación superior en Colombia en el 2021 (Febrero 2021)
  • Informe 27: Grandes retos para la educación básica y media en Colombia en el 2021 (Enero 2021)
  • Informe 26: Resumen de la encuesta diagnóstico del uso de métodos de enseñanza antes y durante el cierre de colegios debido a la pandemia. (Diciembre 2020)
  • Informe 25: Estudiantes venezolanos en Colombia (Noviembre de 2020)
  • Informe 24: Diferencias regionales en el aprendizaje escolar en Colombia (Octubre de 2020)
  • Informe 23: Otros riesgos asociados al cierre de colegios por la pandemia (Octubre de 2020)
  • Informe 22: Los programas de formación en Educación para el Trabajo y Desarrollo Humano (ETDH) y el desempleo. (Septiembre de 2020)
  • Informe 21: Un análisis sobre los programas de las ciencias de la educación. (Septiembre de 2020)
  • Informe 20: Reapertura de colegios: ¿de vuelta a la normalidad? (Agosto de 2020)
  • Informe 19: ¿Cómo ha crecido o decrecido la matrícula total en programas universitarios en Colombia? (Agosto de 2020)
  • Informe 18: Educación básica de los estudiantes indígenas en el marco del Día Internacional de los Pueblos Indígenas 2020 (Agosto de 2020)
  • Informe 17: Gastos e ingresos operacionales de instituciones de educación superior acreditadas y no acreditadas (Agosto de 2020)
  • Informe 16: Proyecciones de la matrícula en educación superior (Julio de 2020)
  • Informe 15: Elección de carreras profesionales: una mirada desde los niveles socioeconómicos (Julio de 2020)
  • Informe 14: Radiografía de la educación escolar (Julio de 2020)
  • Informe 13: Edad de los docentes (Julio de 2020)
  • Informe 12: Medio de desplazamiento de los estudiantes al colegio (Julio de 2020)
  • Informe 11: Matrícula SENA (Junio de 2020)
  • Informe 10: “Matricula $0” e ingresos de las universidades oficiales (Julio de 2020)
  • Informe 9: Radiografía de programas virtuales en pregrado (Junio de 2020)
  • Informe 8: Salud mental y emocional de los niños, niñas y adolescentes (Mayo de 2020)
  • Informe 7: Cifras sobre docentes en el marco del Día del Maestro en Colombia 2020 (Mayo de 2020)
  • Informe 6: Deserción en educación superior (Mayo de 2020)
  • Informe 5: Repitencia escolar en Colombia (Abril de 2020)
  • Informe 4: Deserción escolar en Colombia. (Marzo de 2020)
  • Informe 3: Cobertura de internet y computadores en estudiantes de IES en Colombia. (Marzo de 2020)
  • Informe 2: Competencias digitales de los maestros en Colombia: ¿Están preparados para las clases virtuales? (Marzo de 2020)
  • Informe 1: Cobertura de internet y computadores en estudiantes de colegios oficiales de Colombia. (Marzo de 2020)
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 87:
Lexical error: encountered "u" (117), after "\"Captura de pantalla 2026-02-16 a la(s) 5.40.39\\".
---end-message---

The failing expression:
==> urlimagenString?eval  [in template "20102#20129#5706451" at line 49, column 46]

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

  • Luis Eduardo (2020). Tránsito rezagado a educación superior, una mirada desde la deserción estudiantil.
  • Lady Moreno (2020). Retornos privados de la educación universitaria en Colombia: análisis a partir de los costos de matrícula y de oportunidad.
  • Katherine Turpo (2019). Brechas de genero en el rendimiento académico peruano.
  • Cesar Vega (2018). Relación entre la jornada escolar y las actividades de riesgo juvenil en Colombia.

  • Juan José Florez Wandurraga (2021*) ¿Podría el acceso a un computador y a internet en casa hacer la diferencia en el desempeño de los estudiantes en las pruebas de Estado?
  • Ana Yudy Vera y Harrison Sandoval (2019) ¿Colegios que están expuestos a factores de competencia tienen mejores resultados en las pruebas saber11 que aquellos que no lo están? El caso de Bogotá D.C. Sometido y en revisión. Por sustentar.
  • Oskar Quintero (2018). Efectos de la Acreditación de Alta Calidad sobre el Valor Agregado de las pruebas de Estado. Ganador de la convocatoria de investigación del ICFES 2018.
  • Nathalia Lesmes y Catalina Vallejo (2018). Incompatibilidad existente entre las preferencias de estudio de los individuos y la elección de carrera Caso aplicado a Colombia. Repositorio Pontificia Universidad Javeriana.
  • Niny López (2017). ¿El programa de alimentación escolar contribuye a mejorar el rendimiento académico?: Evaluación del PAE en Colombia. Vniversitas Económica. Vol 17, NO. 11. Winner of junior research grant ICFES 2016.

© Todos los derechos reservados por LEE - Laboratorio de Economía de la Educación - Pontificia Universidad Javeriana
Sujeta a inspección y vigilancia por parte del Ministerio de Educación Nacional (artículo 39 del decreto 1295 de 2010)

FCEA - Dirección: Cra. 7 #40b – 36, Edificio Jorge Hoyos, piso 8 |  (571) 320 8320
Contacto |  lee@javeriana.edu.co |  Siguenos en: