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 ✐</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>
- Abadía, L. K. Bernal, G. L., and Muñoz, S. (2018). Brechas en el desempeño escolar en PISA ¿qué explica la diferencia de Colombia con Finlandia y Chile? Archivos Analíticos de Políticas Educativas, 26 (82).
- Abadía, L K., and Bernal, G. (2017). A Widening Gap? A Gender-Based Analysis of Performance on the Colombian High School Exit Examination. Revista de Economía del Rosario, 20(1), 5-31.
- Soler, S. C. G., Alvarado, L. K. A., & Nisperuza, G. L. B. (2019). Women in STEM: does college boost their performance? Higher Education, 1-18.
- Bernal, G. L., & Penney, J. (2019). Scholarships and student effort: Evidence from Colombia’s ser Pilo Paga program. Economics of Education Review.
- 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: 





