@gem-sdk/swiper 0.0.15-dev.1 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/swiper-bundle.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Swiper 0.0.15-dev.1
2
+ * Swiper 0.0.15
3
3
  * Gem SDK - Swiper, Customized of swiper
4
4
  * https://swiperjs.com
5
5
  *
@@ -879,6 +879,9 @@ var Swiper = (function () {
879
879
 
880
880
  function updateSlides() {
881
881
  const swiper = this;
882
+ function getDirectionPropertyValue(node, label) {
883
+ return parseFloat(node.getPropertyValue(swiper.getDirectionLabel(label)) || 0);
884
+ }
882
885
  const params = swiper.params;
883
886
  const {
884
887
  wrapperEl,
@@ -887,8 +890,10 @@ var Swiper = (function () {
887
890
  rtlTranslate: rtl,
888
891
  wrongRTL
889
892
  } = swiper;
893
+ const isVirtual = swiper.virtual && params.virtual.enabled;
894
+ const previousSlidesLength = isVirtual ? swiper.virtual.slides.length : swiper.slides.length;
890
895
  const slides = elementChildren(slidesEl, `.${swiper.params.slideClass}, swiper-slide`);
891
- const slidesLength = slides.length;
896
+ const slidesLength = isVirtual ? swiper.virtual.slides.length : slides.length;
892
897
  let snapGrid = [];
893
898
  const slidesGrid = [];
894
899
  const slidesSizesGrid = [];
@@ -906,15 +911,15 @@ var Swiper = (function () {
906
911
  let slidePosition = -offsetBefore;
907
912
  let prevSlideSize = 0;
908
913
  let index = 0;
909
- if (typeof swiperSize === 'undefined') return;
914
+ if (typeof swiperSize === 'undefined') {
915
+ return;
916
+ }
910
917
  if (typeof spaceBetween === 'string' && spaceBetween.indexOf('%') >= 0) {
911
918
  spaceBetween = parseFloat(spaceBetween.replace('%', '')) / 100 * swiperSize;
912
919
  } else if (typeof spaceBetween === 'string') {
913
920
  spaceBetween = parseFloat(spaceBetween);
914
921
  }
915
-
916
- // core-lite: compute total slides size without optional modules
917
- swiper.slidesTotalSize = -spaceBetween;
922
+ swiper.virtualSize = -spaceBetween;
918
923
 
919
924
  // reset margins
920
925
  slides.forEach(slideEl => {
@@ -932,34 +937,49 @@ var Swiper = (function () {
932
937
  setCSSProperty(wrapperEl, '--swiper-centered-offset-before', '');
933
938
  setCSSProperty(wrapperEl, '--swiper-centered-offset-after', '');
934
939
  }
940
+ const gridEnabled = params.grid && params.grid.rows > 1 && swiper.grid;
941
+ if (gridEnabled) {
942
+ swiper.grid.initSlides(slides);
943
+ } else if (swiper.grid) {
944
+ swiper.grid.unsetSlides();
945
+ }
935
946
 
936
947
  // Calc slides
937
948
  let slideSize;
938
- const shouldResetSlideSize = params.slidesPerView === 'auto' && params.breakpoints && Object.keys(params.breakpoints).filter(key => typeof params.breakpoints[key].slidesPerView !== 'undefined').length > 0;
949
+ const shouldResetSlideSize = params.slidesPerView === 'auto' && params.breakpoints && Object.keys(params.breakpoints).filter(key => {
950
+ return typeof params.breakpoints[key].slidesPerView !== 'undefined';
951
+ }).length > 0;
939
952
  for (let i = 0; i < slidesLength; i += 1) {
940
953
  slideSize = 0;
941
954
  let slide;
942
955
  if (slides[i]) slide = slides[i];
956
+ if (gridEnabled) {
957
+ swiper.grid.updateSlide(i, slide, slides);
958
+ }
943
959
  if (slides[i] && elementStyle(slide, 'display') === 'none') continue; // eslint-disable-line
944
960
 
945
961
  if (params.slidesPerView === 'auto') {
946
- if (shouldResetSlideSize && slides[i]) {
962
+ if (shouldResetSlideSize) {
947
963
  slides[i].style[swiper.getDirectionLabel('width')] = ``;
948
964
  }
949
965
  const slideStyles = getComputedStyle(slide);
950
966
  const currentTransform = slide.style.transform;
951
967
  const currentWebKitTransform = slide.style.webkitTransform;
952
- if (currentTransform) slide.style.transform = 'none';
953
- if (currentWebKitTransform) slide.style.webkitTransform = 'none';
968
+ if (currentTransform) {
969
+ slide.style.transform = 'none';
970
+ }
971
+ if (currentWebKitTransform) {
972
+ slide.style.webkitTransform = 'none';
973
+ }
954
974
  if (params.roundLengths) {
955
975
  slideSize = swiper.isHorizontal() ? elementOuterSize(slide, 'width', true) : elementOuterSize(slide, 'height', true);
956
976
  } else {
957
977
  // eslint-disable-next-line
958
- const width = parseFloat(slideStyles.getPropertyValue('width')) || slide.offsetWidth;
959
- const paddingLeft = parseFloat(slideStyles.getPropertyValue('padding-left')) || 0;
960
- const paddingRight = parseFloat(slideStyles.getPropertyValue('padding-right')) || 0;
961
- const marginLeft = parseFloat(slideStyles.getPropertyValue('margin-left')) || 0;
962
- const marginRight = parseFloat(slideStyles.getPropertyValue('margin-right')) || 0;
978
+ const width = getDirectionPropertyValue(slideStyles, 'width');
979
+ const paddingLeft = getDirectionPropertyValue(slideStyles, 'padding-left');
980
+ const paddingRight = getDirectionPropertyValue(slideStyles, 'padding-right');
981
+ const marginLeft = getDirectionPropertyValue(slideStyles, 'margin-left');
982
+ const marginRight = getDirectionPropertyValue(slideStyles, 'margin-right');
963
983
  const boxSizing = slideStyles.getPropertyValue('box-sizing');
964
984
  if (boxSizing && boxSizing === 'border-box') {
965
985
  slideSize = width + marginLeft + marginRight;
@@ -971,8 +991,12 @@ var Swiper = (function () {
971
991
  slideSize = width + paddingLeft + paddingRight + marginLeft + marginRight + (offsetWidth - clientWidth);
972
992
  }
973
993
  }
974
- if (currentTransform) slide.style.transform = currentTransform;
975
- if (currentWebKitTransform) slide.style.webkitTransform = currentWebKitTransform;
994
+ if (currentTransform) {
995
+ slide.style.transform = currentTransform;
996
+ }
997
+ if (currentWebKitTransform) {
998
+ slide.style.webkitTransform = currentWebKitTransform;
999
+ }
976
1000
  if (params.roundLengths) slideSize = Math.floor(slideSize);
977
1001
  } else {
978
1002
  slideSize = (swiperSize - (params.slidesPerView - 1) * spaceBetween) / params.slidesPerView;
@@ -981,13 +1005,13 @@ var Swiper = (function () {
981
1005
  slides[i].style[swiper.getDirectionLabel('width')] = `${slideSize}px`;
982
1006
  }
983
1007
  }
984
- if (slides[i]) slides[i].swiperSlideSize = slideSize;
1008
+ if (slides[i]) {
1009
+ slides[i].swiperSlideSize = slideSize;
1010
+ }
985
1011
  slidesSizesGrid.push(slideSize);
986
1012
  if (params.centeredSlides) {
987
1013
  slidePosition = slidePosition + slideSize / 2 + prevSlideSize / 2 + spaceBetween;
988
- if (prevSlideSize === 0 && i !== 0) {
989
- slidePosition = slidePosition - swiperSize / 2 - spaceBetween;
990
- }
1014
+ if (prevSlideSize === 0 && i !== 0) slidePosition = slidePosition - swiperSize / 2 - spaceBetween;
991
1015
  if (i === 0) slidePosition = slidePosition - swiperSize / 2 - spaceBetween;
992
1016
  if (Math.abs(slidePosition) < 1 / 1000) slidePosition = 0;
993
1017
  if (params.roundLengths) slidePosition = Math.floor(slidePosition);
@@ -995,37 +1019,55 @@ var Swiper = (function () {
995
1019
  slidesGrid.push(slidePosition);
996
1020
  } else {
997
1021
  if (params.roundLengths) slidePosition = Math.floor(slidePosition);
998
- if ((index - Math.min(swiper.params.slidesPerGroupSkip, index)) % swiper.params.slidesPerGroup === 0) {
999
- snapGrid.push(slidePosition);
1000
- }
1022
+ if ((index - Math.min(swiper.params.slidesPerGroupSkip, index)) % swiper.params.slidesPerGroup === 0) snapGrid.push(slidePosition);
1001
1023
  slidesGrid.push(slidePosition);
1002
1024
  slidePosition = slidePosition + slideSize + spaceBetween;
1003
1025
  }
1004
- swiper.slidesTotalSize += slideSize + spaceBetween;
1026
+ swiper.virtualSize += slideSize + spaceBetween;
1005
1027
  prevSlideSize = slideSize;
1006
1028
  index += 1;
1007
1029
  }
1008
- swiper.slidesTotalSize = Math.max(swiper.slidesTotalSize, swiperSize) + offsetAfter;
1009
- if (rtl && wrongRTL && params.effect === 'slide') {
1010
- wrapperEl.style.width = `${swiper.slidesTotalSize + spaceBetween}px`;
1030
+ swiper.virtualSize = Math.max(swiper.virtualSize, swiperSize) + offsetAfter;
1031
+ if (rtl && wrongRTL && (params.effect === 'slide' || params.effect === 'coverflow')) {
1032
+ wrapperEl.style.width = `${swiper.virtualSize + spaceBetween}px`;
1011
1033
  }
1012
1034
  if (params.setWrapperSize) {
1013
- wrapperEl.style[swiper.getDirectionLabel('width')] = `${swiper.slidesTotalSize + spaceBetween}px`;
1035
+ wrapperEl.style[swiper.getDirectionLabel('width')] = `${swiper.virtualSize + spaceBetween}px`;
1036
+ }
1037
+ if (gridEnabled) {
1038
+ swiper.grid.updateWrapperSize(slideSize, snapGrid);
1014
1039
  }
1015
1040
 
1016
- // Remove last snap points depending on width (non-centered)
1041
+ // Remove last grid elements depending on width
1017
1042
  if (!params.centeredSlides) {
1018
1043
  const newSlidesGrid = [];
1019
1044
  for (let i = 0; i < snapGrid.length; i += 1) {
1020
1045
  let slidesGridItem = snapGrid[i];
1021
1046
  if (params.roundLengths) slidesGridItem = Math.floor(slidesGridItem);
1022
- if (snapGrid[i] <= swiper.slidesTotalSize - swiperSize) {
1047
+ if (snapGrid[i] <= swiper.virtualSize - swiperSize) {
1023
1048
  newSlidesGrid.push(slidesGridItem);
1024
1049
  }
1025
1050
  }
1026
1051
  snapGrid = newSlidesGrid;
1027
- if (Math.floor(swiper.slidesTotalSize - swiperSize) - Math.floor(snapGrid[snapGrid.length - 1]) > 1) {
1028
- snapGrid.push(swiper.slidesTotalSize - swiperSize);
1052
+ if (Math.floor(swiper.virtualSize - swiperSize) - Math.floor(snapGrid[snapGrid.length - 1]) > 1) {
1053
+ snapGrid.push(swiper.virtualSize - swiperSize);
1054
+ }
1055
+ }
1056
+ if (isVirtual && params.loop) {
1057
+ const size = slidesSizesGrid[0] + spaceBetween;
1058
+ if (params.slidesPerGroup > 1) {
1059
+ const groups = Math.ceil((swiper.virtual.slidesBefore + swiper.virtual.slidesAfter) / params.slidesPerGroup);
1060
+ const groupSize = size * params.slidesPerGroup;
1061
+ for (let i = 0; i < groups; i += 1) {
1062
+ snapGrid.push(snapGrid[snapGrid.length - 1] + groupSize);
1063
+ }
1064
+ }
1065
+ for (let i = 0; i < swiper.virtual.slidesBefore + swiper.virtual.slidesAfter; i += 1) {
1066
+ if (params.slidesPerGroup === 1) {
1067
+ snapGrid.push(snapGrid[snapGrid.length - 1] + size);
1068
+ }
1069
+ slidesGrid.push(slidesGrid[slidesGrid.length - 1] + size);
1070
+ swiper.virtualSize += size;
1029
1071
  }
1030
1072
  }
1031
1073
  if (snapGrid.length === 0) snapGrid = [0];
@@ -1033,7 +1075,9 @@ var Swiper = (function () {
1033
1075
  const key = swiper.isHorizontal() && rtl ? 'marginLeft' : swiper.getDirectionLabel('marginRight');
1034
1076
  slides.filter((_, slideIndex) => {
1035
1077
  if (!params.cssMode || params.loop) return true;
1036
- if (slideIndex === slides.length - 1) return false;
1078
+ if (slideIndex === slides.length - 1) {
1079
+ return false;
1080
+ }
1037
1081
  return true;
1038
1082
  }).forEach(slideEl => {
1039
1083
  slideEl.style[key] = `${spaceBetween}px`;
@@ -1083,9 +1127,7 @@ var Swiper = (function () {
1083
1127
  swiper.snapGrid = swiper.snapGrid.map(v => v + addToSnapGrid);
1084
1128
  swiper.slidesGrid = swiper.slidesGrid.map(v => v + addToSlidesGrid);
1085
1129
  }
1086
-
1087
- // Emit changes
1088
- if (slidesLength !== (previousSlidesGridLength ? slides.length : slides.length)) {
1130
+ if (slidesLength !== previousSlidesLength) {
1089
1131
  swiper.emit('slidesLengthChange');
1090
1132
  }
1091
1133
  if (snapGrid.length !== previousSnapGridLength) {
@@ -1099,7 +1141,7 @@ var Swiper = (function () {
1099
1141
  swiper.updateSlidesOffset();
1100
1142
  }
1101
1143
  swiper.emit('slidesUpdated');
1102
- if (!params.cssMode && params.effect === 'slide') {
1144
+ if (!isVirtual && !params.cssMode && (params.effect === 'slide' || params.effect === 'fade')) {
1103
1145
  const backFaceHiddenClass = `${params.containerModifierClass}backface-hidden`;
1104
1146
  const hasClassBackfaceClassAdded = swiper.el.classList.contains(backFaceHiddenClass);
1105
1147
  if (slidesLength <= params.maxBackfaceHiddenSlides) {
@@ -1113,13 +1155,20 @@ var Swiper = (function () {
1113
1155
  function updateAutoHeight(speed) {
1114
1156
  const swiper = this;
1115
1157
  const activeSlides = [];
1158
+ const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
1159
+ let newHeight = 0;
1160
+ let i;
1116
1161
  if (typeof speed === 'number') {
1117
1162
  swiper.setTransition(speed);
1118
1163
  } else if (speed === true) {
1119
1164
  swiper.setTransition(swiper.params.speed);
1120
1165
  }
1121
- const getSlideByIndex = index => swiper.slides[index];
1122
-
1166
+ const getSlideByIndex = index => {
1167
+ if (isVirtual) {
1168
+ return swiper.slides[swiper.getSlideIndexByData(index)];
1169
+ }
1170
+ return swiper.slides[index];
1171
+ };
1123
1172
  // Find slides currently in view
1124
1173
  if (swiper.params.slidesPerView !== 'auto' && swiper.params.slidesPerView > 1) {
1125
1174
  if (swiper.params.centeredSlides) {
@@ -1127,9 +1176,9 @@ var Swiper = (function () {
1127
1176
  activeSlides.push(slide);
1128
1177
  });
1129
1178
  } else {
1130
- for (let i = 0; i < Math.ceil(swiper.params.slidesPerView); i += 1) {
1179
+ for (i = 0; i < Math.ceil(swiper.params.slidesPerView); i += 1) {
1131
1180
  const index = swiper.activeIndex + i;
1132
- if (index > swiper.slides.length) break;
1181
+ if (index > swiper.slides.length && !isVirtual) break;
1133
1182
  activeSlides.push(getSlideByIndex(index));
1134
1183
  }
1135
1184
  }
@@ -1138,13 +1187,14 @@ var Swiper = (function () {
1138
1187
  }
1139
1188
 
1140
1189
  // Find new height from highest slide in view
1141
- let newHeight = 0;
1142
- for (let i = 0; i < activeSlides.length; i += 1) {
1190
+ for (i = 0; i < activeSlides.length; i += 1) {
1143
1191
  if (typeof activeSlides[i] !== 'undefined') {
1144
1192
  const height = activeSlides[i].offsetHeight;
1145
1193
  newHeight = height > newHeight ? height : newHeight;
1146
1194
  }
1147
1195
  }
1196
+
1197
+ // Update Height
1148
1198
  if (newHeight || newHeight === 0) swiper.wrapperEl.style.height = `${newHeight}px`;
1149
1199
  }
1150
1200
 
@@ -1289,16 +1339,46 @@ var Swiper = (function () {
1289
1339
  slidesEl,
1290
1340
  activeIndex
1291
1341
  } = swiper;
1292
- const getNextSlide = slideEl => elementNextAll(slideEl, `.${params.slideClass}, swiper-slide`)[0];
1293
- const getPrevSlide = slideEl => elementPrevAll(slideEl, `.${params.slideClass}, swiper-slide`)[0];
1294
- const activeSlide = slides[activeIndex];
1295
- let nextSlide;
1342
+ const isVirtual = swiper.virtual && params.virtual.enabled;
1343
+ const gridEnabled = swiper.grid && params.grid && params.grid.rows > 1;
1344
+ const getFilteredSlide = selector => {
1345
+ return elementChildren(slidesEl, `.${params.slideClass}${selector}, swiper-slide${selector}`)[0];
1346
+ };
1347
+ let activeSlide;
1296
1348
  let prevSlide;
1349
+ let nextSlide;
1350
+ if (isVirtual) {
1351
+ if (params.loop) {
1352
+ let slideIndex = activeIndex - swiper.virtual.slidesBefore;
1353
+ if (slideIndex < 0) slideIndex = swiper.virtual.slides.length + slideIndex;
1354
+ if (slideIndex >= swiper.virtual.slides.length) slideIndex -= swiper.virtual.slides.length;
1355
+ activeSlide = getFilteredSlide(`[data-swiper-slide-index="${slideIndex}"]`);
1356
+ } else {
1357
+ activeSlide = getFilteredSlide(`[data-swiper-slide-index="${activeIndex}"]`);
1358
+ }
1359
+ } else {
1360
+ if (gridEnabled) {
1361
+ activeSlide = slides.find(slideEl => slideEl.column === activeIndex);
1362
+ nextSlide = slides.find(slideEl => slideEl.column === activeIndex + 1);
1363
+ prevSlide = slides.find(slideEl => slideEl.column === activeIndex - 1);
1364
+ } else {
1365
+ activeSlide = slides[activeIndex];
1366
+ }
1367
+ }
1297
1368
  if (activeSlide) {
1298
- nextSlide = getNextSlide(activeSlide);
1299
- prevSlide = getPrevSlide(activeSlide);
1300
- if (params.loop && !nextSlide) nextSlide = slides[0];
1301
- if (params.loop && !prevSlide) prevSlide = slides[slides.length - 1];
1369
+ if (!gridEnabled) {
1370
+ // Next Slide
1371
+ nextSlide = elementNextAll(activeSlide, `.${params.slideClass}, swiper-slide`)[0];
1372
+ if (params.loop && !nextSlide) {
1373
+ nextSlide = slides[0];
1374
+ }
1375
+
1376
+ // Prev Slide
1377
+ prevSlide = elementPrevAll(activeSlide, `.${params.slideClass}, swiper-slide`)[0];
1378
+ if (params.loop && !prevSlide === 0) {
1379
+ prevSlide = slides[slides.length - 1];
1380
+ }
1381
+ }
1302
1382
  }
1303
1383
  slides.forEach(slideEl => {
1304
1384
  toggleSlideClasses(slideEl, slideEl === activeSlide, params.slideActiveClass);
@@ -1389,6 +1469,7 @@ var Swiper = (function () {
1389
1469
  activeIndex = i;
1390
1470
  }
1391
1471
  }
1472
+ // Normalize slideIndex
1392
1473
  if (params.normalizeSlideIndex) {
1393
1474
  if (activeIndex < 0 || typeof activeIndex === 'undefined') activeIndex = 0;
1394
1475
  }
@@ -1406,6 +1487,16 @@ var Swiper = (function () {
1406
1487
  } = swiper;
1407
1488
  let activeIndex = newActiveIndex;
1408
1489
  let snapIndex;
1490
+ const getVirtualRealIndex = aIndex => {
1491
+ let realIndex = aIndex - swiper.virtual.slidesBefore;
1492
+ if (realIndex < 0) {
1493
+ realIndex = swiper.virtual.slides.length + realIndex;
1494
+ }
1495
+ if (realIndex >= swiper.virtual.slides.length) {
1496
+ realIndex -= swiper.virtual.slides.length;
1497
+ }
1498
+ return realIndex;
1499
+ };
1409
1500
  if (typeof activeIndex === 'undefined') {
1410
1501
  activeIndex = getActiveIndexByTranslate(swiper);
1411
1502
  }
@@ -1423,12 +1514,32 @@ var Swiper = (function () {
1423
1514
  }
1424
1515
  return;
1425
1516
  }
1426
- let realIndex = activeIndex;
1427
- if (swiper.slides[activeIndex]) {
1517
+ if (activeIndex === previousIndex && swiper.params.loop && swiper.virtual && swiper.params.virtual.enabled) {
1518
+ swiper.realIndex = getVirtualRealIndex(activeIndex);
1519
+ return;
1520
+ }
1521
+ const gridEnabled = swiper.grid && params.grid && params.grid.rows > 1;
1522
+
1523
+ // Get real index
1524
+ let realIndex;
1525
+ if (swiper.virtual && params.virtual.enabled && params.loop) {
1526
+ realIndex = getVirtualRealIndex(activeIndex);
1527
+ } else if (gridEnabled) {
1528
+ const firstSlideInColumn = swiper.slides.find(slideEl => slideEl.column === activeIndex);
1529
+ let activeSlideIndex = parseInt(firstSlideInColumn.getAttribute('data-swiper-slide-index'), 10);
1530
+ if (Number.isNaN(activeSlideIndex)) {
1531
+ activeSlideIndex = Math.max(swiper.slides.indexOf(firstSlideInColumn), 0);
1532
+ }
1533
+ realIndex = Math.floor(activeSlideIndex / params.grid.rows);
1534
+ } else if (swiper.slides[activeIndex]) {
1428
1535
  const slideIndex = swiper.slides[activeIndex].getAttribute('data-swiper-slide-index');
1429
1536
  if (slideIndex) {
1430
1537
  realIndex = parseInt(slideIndex, 10);
1538
+ } else {
1539
+ realIndex = activeIndex;
1431
1540
  }
1541
+ } else {
1542
+ realIndex = activeIndex;
1432
1543
  }
1433
1544
  Object.assign(swiper, {
1434
1545
  previousSnapIndex,
@@ -1475,7 +1586,11 @@ var Swiper = (function () {
1475
1586
  }
1476
1587
  if (slide && slideFound) {
1477
1588
  swiper.clickedSlide = slide;
1478
- swiper.clickedIndex = slideIndex;
1589
+ if (swiper.virtual && swiper.params.virtual.enabled) {
1590
+ swiper.clickedIndex = parseInt(slide.getAttribute('data-swiper-slide-index'), 10);
1591
+ } else {
1592
+ swiper.clickedIndex = slideIndex;
1593
+ }
1479
1594
  } else {
1480
1595
  swiper.clickedSlide = undefined;
1481
1596
  swiper.clickedIndex = undefined;
@@ -1509,6 +1624,9 @@ var Swiper = (function () {
1509
1624
  translate,
1510
1625
  wrapperEl
1511
1626
  } = swiper;
1627
+ if (params.virtualTranslate) {
1628
+ return rtl ? -translate : translate;
1629
+ }
1512
1630
  if (params.cssMode) {
1513
1631
  return translate;
1514
1632
  }
@@ -1542,7 +1660,7 @@ var Swiper = (function () {
1542
1660
  swiper.translate = swiper.isHorizontal() ? x : y;
1543
1661
  if (params.cssMode) {
1544
1662
  wrapperEl[swiper.isHorizontal() ? 'scrollLeft' : 'scrollTop'] = swiper.isHorizontal() ? -x : -y;
1545
- } else {
1663
+ } else if (!params.virtualTranslate) {
1546
1664
  if (swiper.isHorizontal()) {
1547
1665
  x -= swiper.cssOverflowAdjustment();
1548
1666
  } else {
@@ -1779,6 +1897,7 @@ var Swiper = (function () {
1779
1897
  let snapIndex = skip + Math.floor((slideIndex - skip) / swiper.params.slidesPerGroup);
1780
1898
  if (snapIndex >= snapGrid.length) snapIndex = snapGrid.length - 1;
1781
1899
  const translate = -snapGrid[snapIndex];
1900
+ // Normalize slideIndex
1782
1901
  if (params.normalizeSlideIndex) {
1783
1902
  for (let i = 0; i < slidesGrid.length; i += 1) {
1784
1903
  const normalizedTranslate = -Math.floor(translate * 100);
@@ -1795,24 +1914,33 @@ var Swiper = (function () {
1795
1914
  }
1796
1915
  }
1797
1916
  }
1798
-
1799
1917
  // Directions locks
1800
1918
  if (swiper.initialized && slideIndex !== activeIndex) {
1801
1919
  if (!swiper.allowSlideNext && (rtl ? translate > swiper.translate && translate > swiper.minTranslate() : translate < swiper.translate && translate < swiper.minTranslate())) {
1802
1920
  return false;
1803
1921
  }
1804
1922
  if (!swiper.allowSlidePrev && translate > swiper.translate && translate > swiper.maxTranslate()) {
1805
- if ((activeIndex || 0) !== slideIndex) return false;
1923
+ if ((activeIndex || 0) !== slideIndex) {
1924
+ return false;
1925
+ }
1806
1926
  }
1807
1927
  }
1808
1928
  if (slideIndex !== (previousIndex || 0) && runCallbacks) {
1809
1929
  swiper.emit('beforeSlideChangeStart');
1810
1930
  }
1931
+
1932
+ // Update progress
1811
1933
  swiper.updateProgress(translate);
1812
1934
  let direction;
1813
1935
  if (slideIndex > activeIndex) direction = 'next';else if (slideIndex < activeIndex) direction = 'prev';else direction = 'reset';
1814
- if (rtl && -translate === swiper.translate || !rtl && translate === swiper.translate) {
1936
+
1937
+ // initial virtual
1938
+ const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
1939
+ const isInitialVirtual = isVirtual && initial;
1940
+ // Update Index
1941
+ if (!isInitialVirtual && (rtl && -translate === swiper.translate || !rtl && translate === swiper.translate)) {
1815
1942
  swiper.updateActiveIndex(slideIndex);
1943
+ // Update Height
1816
1944
  if (params.autoHeight) {
1817
1945
  swiper.updateAutoHeight();
1818
1946
  }
@@ -1830,7 +1958,24 @@ var Swiper = (function () {
1830
1958
  const isH = swiper.isHorizontal();
1831
1959
  const t = rtl ? translate : -translate;
1832
1960
  if (speed === 0) {
1833
- wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = t;
1961
+ if (isVirtual) {
1962
+ swiper.wrapperEl.style.scrollSnapType = 'none';
1963
+ swiper._immediateVirtual = true;
1964
+ }
1965
+ if (isVirtual && !swiper._cssModeVirtualInitialSet && swiper.params.initialSlide > 0) {
1966
+ swiper._cssModeVirtualInitialSet = true;
1967
+ requestAnimationFrame(() => {
1968
+ wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = t;
1969
+ });
1970
+ } else {
1971
+ wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = t;
1972
+ }
1973
+ if (isVirtual) {
1974
+ requestAnimationFrame(() => {
1975
+ swiper.wrapperEl.style.scrollSnapType = '';
1976
+ swiper._immediateVirtual = false;
1977
+ });
1978
+ }
1834
1979
  } else {
1835
1980
  if (!swiper.support.smoothScroll) {
1836
1981
  animateCSSModeScroll({
@@ -1848,7 +1993,10 @@ var Swiper = (function () {
1848
1993
  return true;
1849
1994
  }
1850
1995
  const browser = getBrowser();
1851
- browser.isSafari;
1996
+ const isSafari = browser.isSafari;
1997
+ if (isVirtual && !initial && isSafari && swiper.isElement) {
1998
+ swiper.virtual.update(false, false, slideIndex);
1999
+ }
1852
2000
  swiper.setTransition(speed);
1853
2001
  swiper.setTranslate(translate);
1854
2002
  swiper.updateActiveIndex(slideIndex);
@@ -2019,6 +2167,8 @@ var Swiper = (function () {
2019
2167
  if (swiper.params?.isSneakPeekCenter && slides.length > 1 && swiper.activeIndex === 0) {
2020
2168
  const gap = Math.abs(swiper.snapGrid[1] - swiper.snapGrid[0]);
2021
2169
  const swiperTranslate = JSON.parse(JSON.stringify(swiper.snapGrid[1]));
2170
+
2171
+ // Move last item to first position only if active slide is the first slide
2022
2172
  const lastSlide = slides[slides.length - 1];
2023
2173
  lastSlide.swiperLoopMoveDOM = true;
2024
2174
  swiper.slidesEl.prepend(lastSlide);
@@ -2053,8 +2203,11 @@ var Swiper = (function () {
2053
2203
  perGroup = Math.max(swiper.slidesPerViewDynamic('current', true), 1);
2054
2204
  }
2055
2205
  const increment = swiper.activeIndex < params.slidesPerGroupSkip ? 1 : perGroup;
2206
+ const isVirtual = swiper.virtual && params.virtual.enabled;
2056
2207
  if (params.loop) {
2057
- if (animating && params.loopPreventsSliding) return false;
2208
+ if (animating && !isVirtual && params.loopPreventsSliding) return false;
2209
+
2210
+ // Kiểm tra xem loop có bị disable không
2058
2211
  const currentSlidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(params.slidesPerView, 10));
2059
2212
  if (swiper.slides.length >= currentSlidesPerView) {
2060
2213
  swiper.loopFix({
@@ -2081,6 +2234,7 @@ var Swiper = (function () {
2081
2234
  const gap = Math.abs(swiper.snapGrid[lastSnapGridIndex] - swiper.snapGrid[lastSnapGridIndex - 1]);
2082
2235
  const swiperTranslate = structuredClone(swiper.snapGrid[lastSnapGridIndex - 1]);
2083
2236
  if (!swiper.params.loop) return;
2237
+ // Move first item to last position only if active slide is the last slide
2084
2238
  const firstSlide = slides[0];
2085
2239
  firstSlide.swiperLoopMoveDOM = true;
2086
2240
  swiper.slidesEl.append(firstSlide);
@@ -2105,14 +2259,17 @@ var Swiper = (function () {
2105
2259
  params,
2106
2260
  snapGrid,
2107
2261
  slidesGrid,
2108
- rtlTranslate: rtlTranslate,
2109
- enabled
2262
+ rtlTranslate,
2263
+ enabled,
2264
+ animating
2110
2265
  } = swiper;
2111
2266
  if (!enabled || swiper.destroyed) return swiper;
2112
2267
  if (typeof speed === 'undefined') {
2113
2268
  speed = swiper.params.speed;
2114
2269
  }
2270
+ swiper.virtual && params.virtual.enabled;
2115
2271
  if (params.loop) {
2272
+ // Kiểm tra xem loop có bị disable không
2116
2273
  const currentSlidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(params.slidesPerView, 10));
2117
2274
  if (swiper.slides.length >= currentSlidesPerView) {
2118
2275
  swiper.loopFix({
@@ -2129,16 +2286,18 @@ var Swiper = (function () {
2129
2286
  }
2130
2287
  const normalizedTranslate = normalize(translate);
2131
2288
  const normalizedSnapGrid = snapGrid.map(val => normalize(val));
2289
+ const isFreeMode = params.freeMode && params.freeMode.enabled;
2132
2290
  let prevSnap = snapGrid[normalizedSnapGrid.indexOf(normalizedTranslate) - 1];
2133
- if (typeof prevSnap === 'undefined' && params.cssMode) {
2291
+ if (typeof prevSnap === 'undefined' && (params.cssMode || isFreeMode)) {
2134
2292
  let prevSnapIndex;
2135
2293
  snapGrid.forEach((snap, snapIndex) => {
2136
2294
  if (normalizedTranslate >= snap) {
2295
+ // prevSnap = snap;
2137
2296
  prevSnapIndex = snapIndex;
2138
2297
  }
2139
2298
  });
2140
2299
  if (typeof prevSnapIndex !== 'undefined') {
2141
- prevSnap = snapGrid[prevSnapIndex > 0 ? prevSnapIndex - 1 : prevSnapIndex];
2300
+ prevSnap = isFreeMode ? snapGrid[prevSnapIndex] : snapGrid[prevSnapIndex > 0 ? prevSnapIndex - 1 : prevSnapIndex];
2142
2301
  }
2143
2302
  }
2144
2303
  let prevIndex = 0;
@@ -2151,7 +2310,7 @@ var Swiper = (function () {
2151
2310
  }
2152
2311
  }
2153
2312
  if (params.rewind && swiper.isBeginning) {
2154
- const lastIndex = swiper.slides.length - 1;
2313
+ const lastIndex = swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual ? swiper.virtual.slides.length - 1 : swiper.slides.length - 1;
2155
2314
  return swiper.slideTo(lastIndex, speed, runCallbacks, internal);
2156
2315
  } else if (params.loop && swiper.activeIndex === 0 && params.cssMode) {
2157
2316
  requestAnimationFrame(() => {
@@ -2165,6 +2324,8 @@ var Swiper = (function () {
2165
2324
  if (swiper.params?.isSneakPeekCenter && slides.length > 1 && swiper.activeIndex === 0) {
2166
2325
  const gap = Math.abs(swiper.snapGrid[1] - swiper.snapGrid[0]);
2167
2326
  const swiperTranslate = JSON.parse(JSON.stringify(swiper.snapGrid[1]));
2327
+
2328
+ // Move last item to first position only if active slide is the first slide
2168
2329
  if (!swiper.params.loop) return;
2169
2330
  const lastSlide = slides[slides.length - 1];
2170
2331
  lastSlide.swiperLoopMoveDOM = true;
@@ -2241,19 +2402,20 @@ var Swiper = (function () {
2241
2402
  slidesEl
2242
2403
  } = swiper;
2243
2404
  const slidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : params.slidesPerView;
2244
- const slideToIndex = swiper.clickedIndex;
2405
+ let slideToIndex = swiper.getSlideIndexWhenGrid(swiper.clickedIndex);
2245
2406
  let realIndex;
2246
2407
  const slideSelector = swiper.isElement ? `swiper-slide` : `.${params.slideClass}`;
2408
+ const isGrid = swiper.grid && swiper.params.grid && swiper.params.grid.rows > 1;
2247
2409
  if (params.loop) {
2248
2410
  if (swiper.animating) return;
2249
2411
  realIndex = parseInt(swiper.clickedSlide.getAttribute('data-swiper-slide-index'), 10);
2250
2412
  if (params.centeredSlides) {
2251
2413
  swiper.slideToLoop(realIndex);
2252
- } else if (slideToIndex > swiper.slides.length - slidesPerView) {
2414
+ } else if (slideToIndex > (isGrid ? (swiper.slides.length - slidesPerView) / 2 - (swiper.params.grid.rows - 1) : swiper.slides.length - slidesPerView)) {
2253
2415
  swiper.loopFix();
2254
- const clickedEl = elementChildren(slidesEl, `${slideSelector}[data-swiper-slide-index="${realIndex}"]`)[0];
2416
+ slideToIndex = swiper.getSlideIndex(elementChildren(slidesEl, `${slideSelector}[data-swiper-slide-index="${realIndex}"]`)[0]);
2255
2417
  nextTick(() => {
2256
- if (clickedEl) swiper.slideTo(swiper.getSlideIndex(clickedEl));
2418
+ swiper.slideTo(slideToIndex);
2257
2419
  });
2258
2420
  } else {
2259
2421
  swiper.slideTo(slideToIndex);
@@ -2280,7 +2442,7 @@ var Swiper = (function () {
2280
2442
  params,
2281
2443
  slidesEl
2282
2444
  } = swiper;
2283
- if (!params.loop) return;
2445
+ if (!params.loop || swiper.virtual && swiper.params.virtual.enabled) return;
2284
2446
  const initSlides = () => {
2285
2447
  const slides = elementChildren(slidesEl, `.${params.slideClass}, swiper-slide`);
2286
2448
  slides.forEach((el, index) => {
@@ -2289,17 +2451,21 @@ var Swiper = (function () {
2289
2451
  };
2290
2452
  const clearBlankSlides = () => {
2291
2453
  const slides = elementChildren(slidesEl, `.${params.slideBlankClass}`);
2292
- slides.forEach(el => el.remove());
2454
+ slides.forEach(el => {
2455
+ el.remove();
2456
+ });
2293
2457
  if (slides.length > 0) {
2294
2458
  swiper.recalcSlides();
2295
2459
  swiper.updateSlides();
2296
2460
  }
2297
2461
  };
2298
- if (params.loopAddBlankSlides && params.slidesPerGroup > 1) {
2462
+ const gridEnabled = swiper.grid && params.grid && params.grid.rows > 1;
2463
+ if (params.loopAddBlankSlides && (params.slidesPerGroup > 1 || gridEnabled)) {
2299
2464
  clearBlankSlides();
2300
2465
  }
2301
- const slidesPerGroup = params.slidesPerGroup;
2466
+ const slidesPerGroup = params.slidesPerGroup * (gridEnabled ? params.grid.rows : 1);
2302
2467
  const shouldFillGroup = swiper.slides.length % slidesPerGroup !== 0;
2468
+ const shouldFillGrid = gridEnabled && swiper.slides.length % params.grid.rows !== 0;
2303
2469
  const addBlankSlides = amountOfSlides => {
2304
2470
  for (let i = 0; i < amountOfSlides; i += 1) {
2305
2471
  const slideEl = swiper.isElement ? createElement('swiper-slide', [params.slideBlankClass]) : createElement('div', [params.slideClass, params.slideBlankClass]);
@@ -2316,6 +2482,16 @@ var Swiper = (function () {
2316
2482
  showWarning('Swiper Loop Warning: The number of slides is not even to slidesPerGroup, loop mode may not function properly. You need to add more slides (or make duplicates, or empty slides)');
2317
2483
  }
2318
2484
  initSlides();
2485
+ } else if (shouldFillGrid) {
2486
+ if (params.loopAddBlankSlides) {
2487
+ const slidesToAdd = params.grid.rows - swiper.slides.length % params.grid.rows;
2488
+ addBlankSlides(slidesToAdd);
2489
+ swiper.recalcSlides();
2490
+ swiper.updateSlides();
2491
+ } else {
2492
+ showWarning('Swiper Loop Warning: The number of slides is not even to grid.rows, loop mode may not function properly. You need to add more slides (or make duplicates, or empty slides)');
2493
+ }
2494
+ initSlides();
2319
2495
  } else {
2320
2496
  initSlides();
2321
2497
  }
@@ -2334,12 +2510,13 @@ var Swiper = (function () {
2334
2510
  setTranslate,
2335
2511
  activeSlideIndex,
2336
2512
  initial,
2513
+ byController,
2337
2514
  byMousewheel
2338
2515
  } = _temp === void 0 ? {} : _temp;
2339
2516
  const swiper = this;
2340
2517
  if (!swiper.params.loop) return;
2341
2518
 
2342
- // Disable loop mode if number of slides is smaller than slidesPerView
2519
+ // Disable loop mode nếu số slides ít hơn slidesPerView
2343
2520
  const currentSlidesPerView = swiper.params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(swiper.params.slidesPerView, 10));
2344
2521
  if (swiper.slides.length < currentSlidesPerView) {
2345
2522
  console.warn('Swiper: Loop mode disabled - slides.length < slidesPerView');
@@ -2359,6 +2536,21 @@ var Swiper = (function () {
2359
2536
  } = params;
2360
2537
  swiper.allowSlidePrev = true;
2361
2538
  swiper.allowSlideNext = true;
2539
+ if (swiper.virtual && params.virtual.enabled) {
2540
+ if (slideTo) {
2541
+ if (!params.centeredSlides && swiper.snapIndex === 0) {
2542
+ swiper.slideTo(swiper.virtual.slides.length, 0, false, true);
2543
+ } else if (params.centeredSlides && swiper.snapIndex < params.slidesPerView) {
2544
+ swiper.slideTo(swiper.virtual.slides.length + swiper.snapIndex, 0, false, true);
2545
+ } else if (swiper.snapIndex === swiper.snapGrid.length - 1) {
2546
+ swiper.slideTo(swiper.virtual.slidesBefore, 0, false, true);
2547
+ }
2548
+ }
2549
+ swiper.allowSlidePrev = allowSlidePrev;
2550
+ swiper.allowSlideNext = allowSlideNext;
2551
+ swiper.emit('loopFix');
2552
+ return;
2553
+ }
2362
2554
  let slidesPerView = params.slidesPerView;
2363
2555
  if (slidesPerView === 'auto') {
2364
2556
  slidesPerView = swiper.slidesPerViewDynamic();
@@ -2368,19 +2560,22 @@ var Swiper = (function () {
2368
2560
  slidesPerView = slidesPerView + 1;
2369
2561
  }
2370
2562
  }
2371
- const slidesPerGroup = params.slidesPerGroup;
2563
+ const slidesPerGroup = params.slidesPerGroupAuto ? slidesPerView : params.slidesPerGroup;
2372
2564
  let loopedSlides = centeredSlides ? Math.max(slidesPerGroup, Math.ceil(slidesPerView / 2)) : slidesPerGroup;
2373
2565
  if (loopedSlides % slidesPerGroup !== 0) {
2374
2566
  loopedSlides += slidesPerGroup - loopedSlides % slidesPerGroup;
2375
2567
  }
2376
2568
  loopedSlides += params.loopAdditionalSlides;
2377
2569
  swiper.loopedSlides = loopedSlides;
2378
- if (slides.length < slidesPerView + loopedSlides) {
2570
+ const gridEnabled = swiper.grid && params.grid && params.grid.rows > 1;
2571
+ if (slides.length < slidesPerView + loopedSlides || swiper.params.effect === 'cards' && slides.length < slidesPerView + loopedSlides * 2) {
2379
2572
  showWarning('Swiper Loop Warning: The number of slides is not enough for loop mode, it will be disabled or not function properly. You need to add more slides (or make duplicates) or lower the values of slidesPerView and slidesPerGroup parameters');
2573
+ } else if (gridEnabled && params.grid.fill === 'row') {
2574
+ showWarning('Swiper Loop Warning: Loop mode is not compatible with grid.fill = `row`');
2380
2575
  }
2381
2576
  const prependSlidesIndexes = [];
2382
2577
  const appendSlidesIndexes = [];
2383
- const cols = slides.length;
2578
+ const cols = gridEnabled ? Math.ceil(slides.length / params.grid.rows) : slides.length;
2384
2579
  const isInitialOverflow = initial && cols - initialSlide < slidesPerView && !centeredSlides;
2385
2580
  let activeIndex = isInitialOverflow ? initialSlide : swiper.activeIndex;
2386
2581
  if (typeof activeSlideIndex === 'undefined') {
@@ -2392,15 +2587,24 @@ var Swiper = (function () {
2392
2587
  const isPrev = direction === 'prev' || !direction;
2393
2588
  let slidesPrepended = 0;
2394
2589
  let slidesAppended = 0;
2395
- const activeColIndex = activeSlideIndex;
2590
+ const activeColIndex = gridEnabled ? slides[activeSlideIndex].column : activeSlideIndex;
2396
2591
  const activeColIndexWithShift = activeColIndex + (centeredSlides && typeof setTranslate === 'undefined' ? -slidesPerView / 2 + 0.5 : 0);
2397
-
2398
2592
  // prepend last slides before start
2399
2593
  if (activeColIndexWithShift < loopedSlides) {
2400
2594
  slidesPrepended = Math.max(loopedSlides - activeColIndexWithShift, slidesPerGroup);
2401
2595
  for (let i = 0; i < loopedSlides - activeColIndexWithShift; i += 1) {
2402
2596
  const index = i - Math.floor(i / cols) * cols;
2403
- prependSlidesIndexes.push(cols - index - 1);
2597
+ if (gridEnabled) {
2598
+ const colIndexToPrepend = cols - index - 1;
2599
+ for (let i = slides.length - 1; i >= 0; i -= 1) {
2600
+ if (slides[i].column === colIndexToPrepend) prependSlidesIndexes.push(i);
2601
+ }
2602
+ // slides.forEach((slide, slideIndex) => {
2603
+ // if (slide.column === colIndexToPrepend) prependSlidesIndexes.push(slideIndex);
2604
+ // });
2605
+ } else {
2606
+ prependSlidesIndexes.push(cols - index - 1);
2607
+ }
2404
2608
  }
2405
2609
  } else if (activeColIndexWithShift + slidesPerView > cols - loopedSlides) {
2406
2610
  slidesAppended = Math.max(activeColIndexWithShift - (cols - loopedSlides * 2), slidesPerGroup);
@@ -2409,13 +2613,27 @@ var Swiper = (function () {
2409
2613
  }
2410
2614
  for (let i = 0; i < slidesAppended; i += 1) {
2411
2615
  const index = i - Math.floor(i / cols) * cols;
2412
- appendSlidesIndexes.push(index);
2616
+ if (gridEnabled) {
2617
+ slides.forEach((slide, slideIndex) => {
2618
+ if (slide.column === index) appendSlidesIndexes.push(slideIndex);
2619
+ });
2620
+ } else {
2621
+ appendSlidesIndexes.push(index);
2622
+ }
2413
2623
  }
2414
2624
  }
2415
2625
  swiper.__preventObserver__ = true;
2416
2626
  requestAnimationFrame(() => {
2417
2627
  swiper.__preventObserver__ = false;
2418
2628
  });
2629
+ if (swiper.params.effect === 'cards' && slides.length < slidesPerView + loopedSlides * 2) {
2630
+ if (appendSlidesIndexes.includes(activeSlideIndex)) {
2631
+ appendSlidesIndexes.splice(appendSlidesIndexes.indexOf(activeSlideIndex), 1);
2632
+ }
2633
+ if (prependSlidesIndexes.includes(activeSlideIndex)) {
2634
+ prependSlidesIndexes.splice(prependSlidesIndexes.indexOf(activeSlideIndex), 1);
2635
+ }
2636
+ }
2419
2637
  if (isPrev) {
2420
2638
  prependSlidesIndexes.forEach(index => {
2421
2639
  slides[index].swiperLoopMoveDOM = true;
@@ -2433,6 +2651,10 @@ var Swiper = (function () {
2433
2651
  swiper.recalcSlides();
2434
2652
  if (params.slidesPerView === 'auto') {
2435
2653
  swiper.updateSlides();
2654
+ } else if (gridEnabled && (prependSlidesIndexes.length > 0 && isPrev || appendSlidesIndexes.length > 0 && isNext)) {
2655
+ swiper.slides.forEach((slide, slideIndex) => {
2656
+ swiper.grid.updateSlide(slideIndex, slide, swiper.slides);
2657
+ });
2436
2658
  }
2437
2659
  if (params.watchSlidesProgress) {
2438
2660
  swiper.updateSlidesOffset();
@@ -2452,10 +2674,12 @@ var Swiper = (function () {
2452
2674
  swiper.touchEventsData.currentTranslate = swiper.touchEventsData.currentTranslate - diff;
2453
2675
  }
2454
2676
  }
2455
- } else if (setTranslate) {
2456
- const shift = prependSlidesIndexes.length;
2457
- swiper.slideTo(swiper.activeIndex + shift, 0, false, true);
2458
- swiper.touchEventsData.currentTranslate = swiper.translate;
2677
+ } else {
2678
+ if (setTranslate) {
2679
+ const shift = gridEnabled ? prependSlidesIndexes.length / params.grid.rows : prependSlidesIndexes.length;
2680
+ swiper.slideTo(swiper.activeIndex + shift, 0, false, true);
2681
+ swiper.touchEventsData.currentTranslate = swiper.translate;
2682
+ }
2459
2683
  }
2460
2684
  } else if (appendSlidesIndexes.length > 0 && isNext) {
2461
2685
  if (typeof slideRealIndex === 'undefined') {
@@ -2471,14 +2695,36 @@ var Swiper = (function () {
2471
2695
  swiper.touchEventsData.currentTranslate = swiper.touchEventsData.currentTranslate - diff;
2472
2696
  }
2473
2697
  }
2474
- } else if (setTranslate) {
2475
- const shift = appendSlidesIndexes.length;
2698
+ } else {
2699
+ const shift = gridEnabled ? appendSlidesIndexes.length / params.grid.rows : appendSlidesIndexes.length;
2476
2700
  swiper.slideTo(swiper.activeIndex - shift, 0, false, true);
2477
2701
  }
2478
2702
  }
2479
2703
  }
2480
2704
  swiper.allowSlidePrev = allowSlidePrev;
2481
2705
  swiper.allowSlideNext = allowSlideNext;
2706
+ if (swiper.controller && swiper.controller.control && !byController) {
2707
+ const loopParams = {
2708
+ slideRealIndex,
2709
+ direction,
2710
+ setTranslate,
2711
+ activeSlideIndex,
2712
+ byController: true
2713
+ };
2714
+ if (Array.isArray(swiper.controller.control)) {
2715
+ swiper.controller.control.forEach(c => {
2716
+ if (!c.destroyed && c.params.loop) c.loopFix({
2717
+ ...loopParams,
2718
+ slideTo: c.params.slidesPerView === params.slidesPerView ? slideTo : false
2719
+ });
2720
+ });
2721
+ } else if (swiper.controller.control instanceof swiper.constructor && swiper.controller.control.params.loop) {
2722
+ swiper.controller.control.loopFix({
2723
+ ...loopParams,
2724
+ slideTo: swiper.controller.control.params.slidesPerView === params.slidesPerView ? slideTo : false
2725
+ });
2726
+ }
2727
+ }
2482
2728
  swiper.emit('loopFix');
2483
2729
  }
2484
2730
 
@@ -2495,7 +2741,7 @@ var Swiper = (function () {
2495
2741
  const swiper = this;
2496
2742
  if (!swiper.params.loop) return;
2497
2743
 
2498
- // Disable loop mode if number of slides is smaller than slidesPerView
2744
+ // Disable loop mode nếu số slides ít hơn slidesPerView
2499
2745
  const currentSlidesPerView = swiper.params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(swiper.params.slidesPerView, 10));
2500
2746
  if (swiper.slides.length < currentSlidesPerView) {
2501
2747
  console.warn('Swiper: Loop mode disabled - slides.length < slidesPerView');
@@ -2534,7 +2780,7 @@ var Swiper = (function () {
2534
2780
  }
2535
2781
  loopedSlides += params.loopAdditionalSlides;
2536
2782
  swiper.loopedSlides = loopedSlides;
2537
- if (slides.length < slidesPerView + loopedSlides) {
2783
+ if (slides.length < slidesPerView + loopedSlides || swiper.params.effect === 'cards' && slides.length < slidesPerView + loopedSlides * 2) {
2538
2784
  showWarning('Swiper Loop Warning: The number of slides is not enough for loop mode, it will be disabled or not function properly. You need to add more slides (or make duplicates) or lower the values of slidesPerView and slidesPerGroup parameters');
2539
2785
  }
2540
2786
  const isNext = direction === 'next' || !direction;
@@ -2560,16 +2806,20 @@ var Swiper = (function () {
2560
2806
  activeSlideIndex = swiper.getSlideIndex(slides.find(el => el.classList.contains(params.slideActiveClass)));
2561
2807
  }
2562
2808
 
2563
- // DocumentFragment to hold slide clones
2809
+ // Tạo DocumentFragment để chứa các slide clone
2564
2810
  const cloneFragment = document.createDocumentFragment();
2565
2811
 
2566
- // Clone slides according to numberOfSlidesNeedClone and append to fragment
2812
+ // Clone các slide theo numberOfSlidesNeedClone (đã đảo ngược) và thêm vào fragment
2567
2813
  (isNext ? numberOfSlidesNeedClone : numberOfSlidesNeedClone.reverse()).forEach(index => {
2568
2814
  if (slides[index]) {
2569
2815
  const originalSlide = slides[index];
2570
2816
  const clonedSlide = originalSlide.cloneNode(true);
2817
+
2818
+ // Đánh dấu slide clone
2571
2819
  clonedSlide.setAttribute('data-swiper-clone', 'true');
2572
2820
  clonedSlide.classList.add('swiper-slide-clone');
2821
+
2822
+ // Thêm clone vào fragment
2573
2823
  cloneFragment.appendChild(clonedSlide);
2574
2824
  }
2575
2825
  });
@@ -2590,28 +2840,32 @@ var Swiper = (function () {
2590
2840
  });
2591
2841
  }
2592
2842
 
2593
- // Sort cloned slides by data-swiper-slide-index
2843
+ // Sắp xếp cloneFragment theo data-swiper-slide-index tăng dần
2594
2844
  const clonedSlides = Array.from(cloneFragment.children);
2595
2845
  clonedSlides.sort((a, b) => {
2596
2846
  const indexA = parseInt(a.getAttribute('data-swiper-slide-index')) || 0;
2597
2847
  const indexB = parseInt(b.getAttribute('data-swiper-slide-index')) || 0;
2598
2848
  return indexA - indexB;
2599
2849
  });
2850
+
2851
+ // Xóa tất cả children cũ và thêm lại theo thứ tự đã sắp xếp
2600
2852
  cloneFragment.innerHTML = '';
2601
2853
  clonedSlides.forEach(slide => {
2602
2854
  cloneFragment.appendChild(slide);
2603
2855
  });
2604
2856
 
2605
- // Place fragment into the right position
2857
+ // Thêm fragment vào vị trí phù hợp
2606
2858
  if (isPrev) {
2859
+ // Nếu là prev, thêm fragment vào cuối slidesEl
2607
2860
  slidesEl.appendChild(cloneFragment);
2608
2861
  } else if (isNext) {
2862
+ // Nếu là next, thêm fragment vào đầu slidesEl
2609
2863
  slidesEl.insertBefore(cloneFragment, slidesEl.firstChild);
2610
2864
  }
2611
2865
  swiper.recalcSlides();
2612
2866
  swiper.updateSlides();
2613
2867
 
2614
- // Find old active slide index after recalculation
2868
+ // Tìm slide data-swiper-slide-index tương ứng
2615
2869
  let oldActiveIndex = null;
2616
2870
  for (let i = 0; i < slidesEl.children.length; i++) {
2617
2871
  const child = slidesEl.children[i];
@@ -2624,7 +2878,7 @@ var Swiper = (function () {
2624
2878
  swiper.slideTo(oldActiveIndex, 0);
2625
2879
  }
2626
2880
 
2627
- // Update translate after removing clones for animation
2881
+ // Tìm vị trí slide cũ sau khi remove clone để set lại translate tạo hiệu ứng animate
2628
2882
  const skip = Math.min(swiper.params.slidesPerGroupSkip, newIndex);
2629
2883
  let snapIndex = skip + Math.floor((newIndex - skip) / swiper.params.slidesPerGroup);
2630
2884
  if (snapIndex >= swiper.snapGrid.length) snapIndex = swiper.snapGrid.length - 1;
@@ -2650,8 +2904,7 @@ var Swiper = (function () {
2650
2904
  }
2651
2905
  swiper.setTranslate(updateTranslate);
2652
2906
  }
2653
-
2654
- // Remove clones
2907
+ // Remove slide clone ra khỏi slidesEl sau khi slideTo hoàn thành
2655
2908
  const cloneSlides = slidesEl.querySelectorAll('[data-swiper-clone="true"]');
2656
2909
  cloneSlides.forEach(cloneSlide => {
2657
2910
  if (cloneSlide.parentNode) {
@@ -2681,7 +2934,7 @@ var Swiper = (function () {
2681
2934
  params,
2682
2935
  slidesEl
2683
2936
  } = swiper;
2684
- if (!params.loop || !slidesEl) return;
2937
+ if (!params.loop || !slidesEl || swiper.virtual && swiper.params.virtual.enabled) return;
2685
2938
  swiper.recalcSlides();
2686
2939
  const newSlidesOrder = [];
2687
2940
  swiper.slides.forEach(slideEl => {
@@ -2742,6 +2995,7 @@ var Swiper = (function () {
2742
2995
  unsetGrabCursor
2743
2996
  };
2744
2997
 
2998
+ // Modified from https://stackoverflow.com/questions/54520554/custom-element-getrootnode-closest-function-crossing-multiple-parent-shadowd
2745
2999
  function closestElement(selector, base) {
2746
3000
  if (base === void 0) {
2747
3001
  base = this;
@@ -2750,7 +3004,9 @@ var Swiper = (function () {
2750
3004
  if (!el || el === getDocument() || el === getWindow()) return null;
2751
3005
  if (el.assignedSlot) el = el.assignedSlot;
2752
3006
  const found = el.closest(selector);
2753
- if (!found && !el.getRootNode) return null;
3007
+ if (!found && !el.getRootNode) {
3008
+ return null;
3009
+ }
2754
3010
  return found || __closestFrom(el.getRootNode().host);
2755
3011
  }
2756
3012
  return __closestFrom(base);
@@ -2778,7 +3034,9 @@ var Swiper = (function () {
2778
3034
  if (e.originalEvent) e = e.originalEvent;
2779
3035
  const data = swiper.touchEventsData;
2780
3036
  if (e.type === 'pointerdown') {
2781
- if (data.pointerId !== null && data.pointerId !== e.pointerId) return;
3037
+ if (data.pointerId !== null && data.pointerId !== e.pointerId) {
3038
+ return;
3039
+ }
2782
3040
  data.pointerId = e.pointerId;
2783
3041
  } else if (e.type === 'touchstart' && e.targetTouches.length === 1) {
2784
3042
  data.touchId = e.targetTouches[0].identifier;
@@ -2795,7 +3053,9 @@ var Swiper = (function () {
2795
3053
  } = swiper;
2796
3054
  if (!enabled) return;
2797
3055
  if (!params.simulateTouch && e.pointerType === 'mouse') return;
2798
- if (swiper.animating && params.preventInteractionOnTransition) return;
3056
+ if (swiper.animating && params.preventInteractionOnTransition) {
3057
+ return;
3058
+ }
2799
3059
  if (!swiper.animating && params.cssMode && params.loop) {
2800
3060
  swiper.loopFix();
2801
3061
  }
@@ -2806,6 +3066,8 @@ var Swiper = (function () {
2806
3066
  if ('which' in e && e.which === 3) return;
2807
3067
  if ('button' in e && e.button > 0) return;
2808
3068
  if (data.isTouched && data.isMoved) return;
3069
+
3070
+ // change target el for shadow root component
2809
3071
  const swipingClassHasValue = !!params.noSwipingClass && params.noSwipingClass !== '';
2810
3072
  // eslint-disable-next-line
2811
3073
  const eventPath = e.composedPath ? e.composedPath() : e.path;
@@ -2814,6 +3076,8 @@ var Swiper = (function () {
2814
3076
  }
2815
3077
  const noSwipingSelector = params.noSwipingSelector ? params.noSwipingSelector : `.${params.noSwipingClass}`;
2816
3078
  const isTargetShadow = !!(e.target && e.target.shadowRoot);
3079
+
3080
+ // use closestElement for shadow root element to get the actual closest for nested shadow root element
2817
3081
  if (params.noSwiping && (isTargetShadow ? closestElement(noSwipingSelector, targetEl) : targetEl.closest(noSwipingSelector))) {
2818
3082
  swiper.allowClick = true;
2819
3083
  return;
@@ -2825,7 +3089,12 @@ var Swiper = (function () {
2825
3089
  touches.currentY = e.pageY;
2826
3090
  const startX = touches.currentX;
2827
3091
  const startY = touches.currentY;
2828
- if (!preventEdgeSwipe(swiper, e, startX)) return;
3092
+
3093
+ // Do NOT start if iOS edge swipe is detected. Otherwise iOS app cannot swipe-to-go-back anymore
3094
+
3095
+ if (!preventEdgeSwipe(swiper, e, startX)) {
3096
+ return;
3097
+ }
2829
3098
  Object.assign(data, {
2830
3099
  isTouched: true,
2831
3100
  isMoved: false,
@@ -2854,6 +3123,9 @@ var Swiper = (function () {
2854
3123
  if ((params.touchStartForcePreventDefault || shouldPreventDefault) && !targetEl.isContentEditable) {
2855
3124
  e.preventDefault();
2856
3125
  }
3126
+ if (params.freeMode && params.freeMode.enabled && swiper.freeMode && swiper.animating && !params.cssMode) {
3127
+ swiper.freeMode.onTouchStart();
3128
+ }
2857
3129
  swiper.emit('touchStart', e);
2858
3130
  }
2859
3131
 
@@ -2872,7 +3144,7 @@ var Swiper = (function () {
2872
3144
  let e = event;
2873
3145
  if (e.originalEvent) e = e.originalEvent;
2874
3146
  if (e.type === 'pointermove') {
2875
- if (data.touchId !== null) return;
3147
+ if (data.touchId !== null) return; // return from pointer if we use touch
2876
3148
  const id = e.pointerId;
2877
3149
  if (id !== data.pointerId) return;
2878
3150
  }
@@ -2913,6 +3185,7 @@ var Swiper = (function () {
2913
3185
  }
2914
3186
  if (params.touchReleaseOnEdges && !params.loop) {
2915
3187
  if (swiper.isVertical()) {
3188
+ // Vertical
2916
3189
  if (pageY < touches.startY && swiper.translate <= swiper.maxTranslate() || pageY > touches.startY && swiper.translate >= swiper.minTranslate()) {
2917
3190
  data.isTouched = false;
2918
3191
  data.isMoved = false;
@@ -3014,6 +3287,7 @@ var Swiper = (function () {
3014
3287
  swiper.wrapperEl.dispatchEvent(evt);
3015
3288
  }
3016
3289
  data.allowMomentumBounce = false;
3290
+ // Grab Cursor
3017
3291
  if (params.grabCursor && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {
3018
3292
  swiper.setGrabCursor(true);
3019
3293
  }
@@ -3084,6 +3358,8 @@ var Swiper = (function () {
3084
3358
  if (!swiper.allowSlidePrev && !swiper.allowSlideNext) {
3085
3359
  data.currentTranslate = data.startTranslate;
3086
3360
  }
3361
+
3362
+ // Threshold
3087
3363
  if (params.threshold > 0) {
3088
3364
  if (Math.abs(diff) > params.threshold || data.allowThresholdMove) {
3089
3365
  if (!data.allowThresholdMove) {
@@ -3101,12 +3377,17 @@ var Swiper = (function () {
3101
3377
  }
3102
3378
  if (!params.followFinger || params.cssMode) return;
3103
3379
 
3104
- // core-lite: no optional feature updates; only watchSlidesProgress
3105
- if (params.watchSlidesProgress) {
3380
+ // Update active index in free mode
3381
+ if (params.freeMode && params.freeMode.enabled && swiper.freeMode || params.watchSlidesProgress) {
3106
3382
  swiper.updateActiveIndex();
3107
3383
  swiper.updateSlidesClasses();
3108
3384
  }
3385
+ if (params.freeMode && params.freeMode.enabled && swiper.freeMode) {
3386
+ swiper.freeMode.onTouchMove();
3387
+ }
3388
+ // Update progress
3109
3389
  swiper.updateProgress(data.currentTranslate);
3390
+ // Update translate
3110
3391
  swiper.setTranslate(data.currentTranslate);
3111
3392
  }
3112
3393
 
@@ -3118,7 +3399,7 @@ var Swiper = (function () {
3118
3399
  let targetTouch;
3119
3400
  const isTouchEvent = e.type === 'touchend' || e.type === 'touchcancel';
3120
3401
  if (!isTouchEvent) {
3121
- if (data.touchId !== null) return;
3402
+ if (data.touchId !== null) return; // return from pointer if we use touch
3122
3403
  if (e.pointerId !== data.pointerId) return;
3123
3404
  targetTouch = e;
3124
3405
  } else {
@@ -3127,7 +3408,9 @@ var Swiper = (function () {
3127
3408
  }
3128
3409
  if (['pointercancel', 'pointerout', 'pointerleave', 'contextmenu'].includes(e.type)) {
3129
3410
  const proceed = ['pointercancel', 'contextmenu'].includes(e.type) && (swiper.browser.isSafari || swiper.browser.isWebView);
3130
- if (!proceed) return;
3411
+ if (!proceed) {
3412
+ return;
3413
+ }
3131
3414
  }
3132
3415
  data.pointerId = null;
3133
3416
  data.touchId = null;
@@ -3145,7 +3428,9 @@ var Swiper = (function () {
3145
3428
  }
3146
3429
  data.allowTouchCallbacks = false;
3147
3430
  if (!data.isTouched) {
3148
- if (data.isMoved && params.grabCursor) swiper.setGrabCursor(false);
3431
+ if (data.isMoved && params.grabCursor) {
3432
+ swiper.setGrabCursor(false);
3433
+ }
3149
3434
  data.isMoved = false;
3150
3435
  data.startMoving = false;
3151
3436
  return;
@@ -3155,6 +3440,8 @@ var Swiper = (function () {
3155
3440
  if (params.grabCursor && data.isMoved && data.isTouched && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {
3156
3441
  swiper.setGrabCursor(false);
3157
3442
  }
3443
+
3444
+ // Time diff
3158
3445
  const touchEndTime = now();
3159
3446
  const timeDiff = touchEndTime - data.touchStartTime;
3160
3447
 
@@ -3181,8 +3468,20 @@ var Swiper = (function () {
3181
3468
  data.isMoved = false;
3182
3469
  data.startMoving = false;
3183
3470
  let currentPos;
3184
- if (params.followFinger) currentPos = rtl ? swiper.translate : -swiper.translate;else currentPos = -data.currentTranslate;
3185
- if (params.cssMode) return;
3471
+ if (params.followFinger) {
3472
+ currentPos = rtl ? swiper.translate : -swiper.translate;
3473
+ } else {
3474
+ currentPos = -data.currentTranslate;
3475
+ }
3476
+ if (params.cssMode) {
3477
+ return;
3478
+ }
3479
+ if (params.freeMode && params.freeMode.enabled) {
3480
+ swiper.freeMode.onTouchEnd({
3481
+ currentPos
3482
+ });
3483
+ return;
3484
+ }
3186
3485
 
3187
3486
  // Find current slide
3188
3487
  const swipeToLast = currentPos >= -swiper.maxTranslate() && !swiper.params.loop;
@@ -3204,22 +3503,22 @@ var Swiper = (function () {
3204
3503
  let rewindLastIndex = null;
3205
3504
  if (params.rewind) {
3206
3505
  if (swiper.isBeginning) {
3207
- rewindLastIndex = swiper.slides.length - 1;
3506
+ rewindLastIndex = params.virtual && params.virtual.enabled && swiper.virtual ? swiper.virtual.slides.length - 1 : swiper.slides.length - 1;
3208
3507
  } else if (swiper.isEnd) {
3209
3508
  rewindFirstIndex = 0;
3210
3509
  }
3211
3510
  }
3511
+ // Find current slide size
3212
3512
  const ratio = (currentPos - slidesGrid[stopIndex]) / groupSize;
3213
3513
  const increment = stopIndex < params.slidesPerGroupSkip - 1 ? 1 : params.slidesPerGroup;
3214
3514
  if (timeDiff > params.longSwipesMs) {
3515
+ // Long touches
3215
3516
  if (!params.longSwipes) {
3216
3517
  swiper.slideTo(swiper.activeIndex);
3217
3518
  return;
3218
3519
  }
3219
3520
  if (swiper.swipeDirection === 'next') {
3220
- if (ratio >= params.longSwipesRatio) {
3221
- swiper.slideTo(params.rewind && swiper.isEnd ? rewindFirstIndex : stopIndex + increment);
3222
- } else swiper.slideTo(stopIndex);
3521
+ if (ratio >= params.longSwipesRatio) swiper.slideTo(params.rewind && swiper.isEnd ? rewindFirstIndex : stopIndex + increment);else swiper.slideTo(stopIndex);
3223
3522
  }
3224
3523
  if (swiper.swipeDirection === 'prev') {
3225
3524
  if (ratio > 1 - params.longSwipesRatio) {
@@ -3271,6 +3570,7 @@ var Swiper = (function () {
3271
3570
  allowSlidePrev,
3272
3571
  snapGrid
3273
3572
  } = swiper;
3573
+ const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
3274
3574
 
3275
3575
  // Disable locks on resize
3276
3576
  swiper.allowSlideNext = true;
@@ -3278,12 +3578,15 @@ var Swiper = (function () {
3278
3578
  swiper.updateSize();
3279
3579
  swiper.updateSlides();
3280
3580
  swiper.updateSlidesClasses();
3281
- if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !swiper.isBeginning && !swiper.params.centeredSlides) {
3581
+ const isVirtualLoop = isVirtual && params.loop;
3582
+ if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !swiper.isBeginning && !swiper.params.centeredSlides && !isVirtualLoop) {
3282
3583
  swiper.slideTo(swiper.slides.length - 1, 0, false, true);
3283
- } else if (swiper.params.loop) {
3284
- swiper.slideToLoop(swiper.realIndex, 0, false, true);
3285
3584
  } else {
3286
- swiper.slideTo(swiper.activeIndex, 0, false, true);
3585
+ if (swiper.params.loop && !isVirtual) {
3586
+ swiper.slideToLoop(swiper.realIndex, 0, false, true);
3587
+ } else {
3588
+ swiper.slideTo(swiper.activeIndex, 0, false, true);
3589
+ }
3287
3590
  }
3288
3591
  if (swiper.autoplay && swiper.autoplay.running && swiper.autoplay.paused) {
3289
3592
  clearTimeout(swiper.autoplay.resizeTimeout);
@@ -3293,11 +3596,10 @@ var Swiper = (function () {
3293
3596
  }
3294
3597
  }, 500);
3295
3598
  }
3296
-
3297
3599
  // Return locks after resize
3298
3600
  swiper.allowSlidePrev = allowSlidePrev;
3299
3601
  swiper.allowSlideNext = allowSlideNext;
3300
- if (params.watchOverflow && snapGrid !== swiper.snapGrid) {
3602
+ if (swiper.params.watchOverflow && snapGrid !== swiper.snapGrid) {
3301
3603
  swiper.checkOverflow();
3302
3604
  }
3303
3605
  }
@@ -3351,10 +3653,6 @@ var Swiper = (function () {
3351
3653
  if (swiper.params.cssMode || swiper.params.slidesPerView !== 'auto' && !swiper.params.autoHeight) {
3352
3654
  return;
3353
3655
  }
3354
- const el = e?.target;
3355
- // IMG, IFRAME, EMBED with width/height attributes don't change slide size — no need to call swiper.update()
3356
- if (!el || !['IMG', 'IFRAME', 'EMBED'].includes(el.tagName)) return;
3357
- if (el.hasAttribute('width') && el.hasAttribute('height')) return;
3358
3656
  swiper.update();
3359
3657
  }
3360
3658
 
@@ -3466,15 +3764,8 @@ var Swiper = (function () {
3466
3764
  detachEvents
3467
3765
  };
3468
3766
 
3469
- const toggleModule = (swiper, params, breakpointParams, prop) => {
3470
- const wasModuleEnabled = params[prop] && params[prop].enabled;
3471
- const isModuleEnabled = breakpointParams[prop] && breakpointParams[prop].enabled;
3472
- if (wasModuleEnabled && !isModuleEnabled) {
3473
- swiper[prop].disable();
3474
- }
3475
- if (!wasModuleEnabled && isModuleEnabled) {
3476
- swiper[prop].enable();
3477
- }
3767
+ const isGridEnabled = (swiper, params) => {
3768
+ return swiper.grid && params.grid && params.grid.rows > 1;
3478
3769
  };
3479
3770
  function setBreakpoint() {
3480
3771
  const swiper = this;
@@ -3495,20 +3786,38 @@ var Swiper = (function () {
3495
3786
  if (!breakpoint || swiper.currentBreakpoint === breakpoint) return;
3496
3787
  const breakpointOnlyParams = breakpoint in breakpoints ? breakpoints[breakpoint] : undefined;
3497
3788
  const breakpointParams = breakpointOnlyParams || swiper.originalParams;
3789
+ const wasMultiRow = isGridEnabled(swiper, params);
3790
+ const isMultiRow = isGridEnabled(swiper, breakpointParams);
3498
3791
  const wasGrabCursor = swiper.params.grabCursor;
3499
3792
  const isGrabCursor = breakpointParams.grabCursor;
3500
3793
  const wasEnabled = params.enabled;
3794
+ if (wasMultiRow && !isMultiRow) {
3795
+ el.classList.remove(`${params.containerModifierClass}grid`, `${params.containerModifierClass}grid-column`);
3796
+ swiper.emitContainerClasses();
3797
+ } else if (!wasMultiRow && isMultiRow) {
3798
+ el.classList.add(`${params.containerModifierClass}grid`);
3799
+ if (breakpointParams.grid.fill && breakpointParams.grid.fill === 'column' || !breakpointParams.grid.fill && params.grid.fill === 'column') {
3800
+ el.classList.add(`${params.containerModifierClass}grid-column`);
3801
+ }
3802
+ swiper.emitContainerClasses();
3803
+ }
3501
3804
  if (wasGrabCursor && !isGrabCursor) {
3502
3805
  swiper.unsetGrabCursor();
3503
3806
  } else if (!wasGrabCursor && isGrabCursor) {
3504
3807
  swiper.setGrabCursor();
3505
3808
  }
3506
3809
 
3507
- // Core-lite: toggle navigation & pagination only.
3508
- const modules = ['navigation', 'pagination'];
3509
- modules.forEach(prop => {
3810
+ // Toggle navigation, pagination, scrollbar
3811
+ ['navigation', 'pagination', 'scrollbar'].forEach(prop => {
3510
3812
  if (typeof breakpointParams[prop] === 'undefined') return;
3511
- toggleModule(swiper, params, breakpointParams, prop);
3813
+ const wasModuleEnabled = params[prop] && params[prop].enabled;
3814
+ const isModuleEnabled = breakpointParams[prop] && breakpointParams[prop].enabled;
3815
+ if (wasModuleEnabled && !isModuleEnabled) {
3816
+ swiper[prop].disable();
3817
+ }
3818
+ if (!wasModuleEnabled && isModuleEnabled) {
3819
+ swiper[prop].enable();
3820
+ }
3512
3821
  });
3513
3822
  const directionChanged = breakpointParams.direction && breakpointParams.direction !== params.direction;
3514
3823
  const needsReLoop = params.loop && (breakpointParams.slidesPerView !== params.slidesPerView || directionChanged);
@@ -3590,7 +3899,7 @@ var Swiper = (function () {
3590
3899
  getBreakpoint
3591
3900
  };
3592
3901
 
3593
- const prepareClasses = (entries, prefix) => {
3902
+ function prepareClasses(entries, prefix) {
3594
3903
  const resultClasses = [];
3595
3904
  entries.forEach(item => {
3596
3905
  if (typeof item === 'object') {
@@ -3604,7 +3913,7 @@ var Swiper = (function () {
3604
3913
  }
3605
3914
  });
3606
3915
  return resultClasses;
3607
- };
3916
+ }
3608
3917
  function addClasses() {
3609
3918
  const swiper = this;
3610
3919
  const {
@@ -3614,12 +3923,17 @@ var Swiper = (function () {
3614
3923
  el,
3615
3924
  device
3616
3925
  } = swiper;
3617
- // core-lite: removed module-specific classes
3618
3926
  // prettier-ignore
3619
3927
  const suffixes = prepareClasses(['initialized', params.direction, {
3928
+ 'free-mode': swiper.params.freeMode && params.freeMode.enabled
3929
+ }, {
3620
3930
  'autoheight': params.autoHeight
3621
3931
  }, {
3622
3932
  'rtl': rtl
3933
+ }, {
3934
+ 'grid': params.grid && params.grid.rows > 1
3935
+ }, {
3936
+ 'grid-column': params.grid && params.grid.rows > 1 && params.grid.fill === 'column'
3623
3937
  }, {
3624
3938
  'android': device.android
3625
3939
  }, {
@@ -3716,12 +4030,16 @@ var Swiper = (function () {
3716
4030
  autoHeight: false,
3717
4031
  // Set wrapper width
3718
4032
  setWrapperSize: false,
3719
- // Effects (core-lite only supports `slide`)
4033
+ // Virtual Translate
4034
+ virtualTranslate: false,
4035
+ // Effects
3720
4036
  effect: 'slide',
4037
+ // 'slide' or 'fade' or 'cube' or 'coverflow' or 'flip'
4038
+
3721
4039
  // Breakpoints
3722
4040
  breakpoints: undefined,
3723
4041
  breakpointsBase: 'window',
3724
- // Slides
4042
+ // Slides grid
3725
4043
  spaceBetween: 0,
3726
4044
  slidesPerView: 1,
3727
4045
  slidesPerGroup: 1,
@@ -3824,9 +4142,7 @@ var Swiper = (function () {
3824
4142
  if (moduleParamName === 'navigation' && params[moduleParamName] && params[moduleParamName].enabled && !params[moduleParamName].prevEl && !params[moduleParamName].nextEl) {
3825
4143
  params[moduleParamName].auto = true;
3826
4144
  }
3827
-
3828
- // Core-lite: keep only pagination auto-init.
3829
- if (moduleParamName === 'pagination' && params[moduleParamName] && params[moduleParamName].enabled && !params[moduleParamName].el) {
4145
+ if (['pagination', 'scrollbar'].indexOf(moduleParamName) >= 0 && params[moduleParamName] && params[moduleParamName].enabled && !params[moduleParamName].el) {
3830
4146
  params[moduleParamName].auto = true;
3831
4147
  }
3832
4148
  if (!(moduleParamName in params && 'enabled' in moduleParams)) {
@@ -3952,6 +4268,7 @@ var Swiper = (function () {
3952
4268
  // Indexes
3953
4269
  activeIndex: 0,
3954
4270
  realIndex: 0,
4271
+ //
3955
4272
  isBeginning: true,
3956
4273
  isEnd: false,
3957
4274
  // Props
@@ -3978,9 +4295,12 @@ var Swiper = (function () {
3978
4295
  currentTranslate: undefined,
3979
4296
  startTranslate: undefined,
3980
4297
  allowThresholdMove: undefined,
4298
+ // Form elements to match
3981
4299
  focusableElements: swiper.params.focusableElements,
4300
+ // Last click time
3982
4301
  lastClickTime: 0,
3983
4302
  clickTimeout: undefined,
4303
+ // Velocities
3984
4304
  velocities: [],
3985
4305
  allowMomentumBounce: undefined,
3986
4306
  startMoving: undefined,
@@ -4009,6 +4329,7 @@ var Swiper = (function () {
4009
4329
  swiper.init();
4010
4330
  }
4011
4331
 
4332
+ // Return app instance
4012
4333
  // eslint-disable-next-line no-constructor-return
4013
4334
  return swiper;
4014
4335
  }
@@ -4040,6 +4361,16 @@ var Swiper = (function () {
4040
4361
  getSlideIndexByData(index) {
4041
4362
  return this.getSlideIndex(this.slides.find(slideEl => slideEl.getAttribute('data-swiper-slide-index') * 1 === index));
4042
4363
  }
4364
+ getSlideIndexWhenGrid(index) {
4365
+ if (this.grid && this.params.grid && this.params.grid.rows > 1) {
4366
+ if (this.params.grid.fill === 'column') {
4367
+ index = Math.floor(index / this.params.grid.rows);
4368
+ } else if (this.params.grid.fill === 'row') {
4369
+ index = index % Math.ceil(this.slides.length / this.params.grid.rows);
4370
+ }
4371
+ }
4372
+ return index;
4373
+ }
4043
4374
  recalcSlides() {
4044
4375
  const swiper = this;
4045
4376
  const {
@@ -4141,15 +4472,21 @@ var Swiper = (function () {
4141
4472
  }
4142
4473
  }
4143
4474
  } else {
4475
+ // eslint-disable-next-line
4144
4476
  if (view === 'current') {
4145
4477
  for (let i = activeIndex + 1; i < slides.length; i += 1) {
4146
4478
  const slideInView = exact ? slidesGrid[i] + slidesSizesGrid[i] - slidesGrid[activeIndex] < swiperSize : slidesGrid[i] - slidesGrid[activeIndex] < swiperSize;
4147
- if (slideInView) spv += 1;
4479
+ if (slideInView) {
4480
+ spv += 1;
4481
+ }
4148
4482
  }
4149
4483
  } else {
4484
+ // previous
4150
4485
  for (let i = activeIndex - 1; i >= 0; i -= 1) {
4151
4486
  const slideInView = slidesGrid[activeIndex] - slidesGrid[i] < swiperSize;
4152
- if (slideInView) spv += 1;
4487
+ if (slideInView) {
4488
+ spv += 1;
4489
+ }
4153
4490
  }
4154
4491
  }
4155
4492
  }
@@ -4162,11 +4499,14 @@ var Swiper = (function () {
4162
4499
  snapGrid,
4163
4500
  params
4164
4501
  } = swiper;
4502
+ // Breakpoints
4165
4503
  if (params.breakpoints) {
4166
4504
  swiper.setBreakpoint();
4167
4505
  }
4168
4506
  [...swiper.el.querySelectorAll('[loading="lazy"]')].forEach(imageEl => {
4169
- if (imageEl.complete) processLazyPreloader(swiper, imageEl);
4507
+ if (imageEl.complete) {
4508
+ processLazyPreloader(swiper, imageEl);
4509
+ }
4170
4510
  });
4171
4511
  swiper.updateSize();
4172
4512
  swiper.updateSlides();
@@ -4180,12 +4520,22 @@ var Swiper = (function () {
4180
4520
  swiper.updateSlidesClasses();
4181
4521
  }
4182
4522
  let translated;
4183
- if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !params.centeredSlides) {
4184
- translated = swiper.slideTo(swiper.slides.length - 1, 0, false, true);
4523
+ if (params.freeMode && params.freeMode.enabled && !params.cssMode) {
4524
+ setTranslate();
4525
+ if (params.autoHeight) {
4526
+ swiper.updateAutoHeight();
4527
+ }
4185
4528
  } else {
4186
- translated = swiper.slideTo(swiper.activeIndex, 0, false, true);
4529
+ if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !params.centeredSlides) {
4530
+ const slides = swiper.virtual && params.virtual.enabled ? swiper.virtual.slides : swiper.slides;
4531
+ translated = swiper.slideTo(slides.length - 1, 0, false, true);
4532
+ } else {
4533
+ translated = swiper.slideTo(swiper.activeIndex, 0, false, true);
4534
+ }
4535
+ if (!translated) {
4536
+ setTranslate();
4537
+ }
4187
4538
  }
4188
- if (!translated) setTranslate();
4189
4539
  if (params.watchOverflow && snapGrid !== swiper.snapGrid) {
4190
4540
  swiper.checkOverflow();
4191
4541
  }
@@ -4198,6 +4548,7 @@ var Swiper = (function () {
4198
4548
  const swiper = this;
4199
4549
  const currentDirection = swiper.params.direction;
4200
4550
  if (!newDirection) {
4551
+ // eslint-disable-next-line
4201
4552
  newDirection = currentDirection === 'horizontal' ? 'vertical' : 'horizontal';
4202
4553
  }
4203
4554
  if (newDirection === currentDirection || newDirection !== 'horizontal' && newDirection !== 'vertical') {
@@ -4235,11 +4586,15 @@ var Swiper = (function () {
4235
4586
  mount(element) {
4236
4587
  const swiper = this;
4237
4588
  if (swiper.mounted) return true;
4589
+
4590
+ // Find el
4238
4591
  let el = element || swiper.params.el;
4239
4592
  if (typeof el === 'string') {
4240
4593
  el = document.querySelector(el);
4241
4594
  }
4242
- if (!el) return false;
4595
+ if (!el) {
4596
+ return false;
4597
+ }
4243
4598
  el.swiper = swiper;
4244
4599
  if (el.parentNode && el.parentNode.host && el.parentNode.host.nodeName === swiper.params.swiperElementNodeName.toUpperCase()) {
4245
4600
  swiper.isElement = true;
@@ -4250,10 +4605,12 @@ var Swiper = (function () {
4250
4605
  const getWrapper = () => {
4251
4606
  if (el && el.shadowRoot && el.shadowRoot.querySelector) {
4252
4607
  const res = el.shadowRoot.querySelector(getWrapperSelector());
4608
+ // Children needs to return slot items
4253
4609
  return res;
4254
4610
  }
4255
4611
  return elementChildren(el, getWrapperSelector())[0];
4256
4612
  };
4613
+ // Find Wrapper
4257
4614
  let wrapperEl = getWrapper();
4258
4615
  if (!wrapperEl && swiper.params.createElements) {
4259
4616
  wrapperEl = createElement('div', swiper.params.wrapperClass);
@@ -4268,6 +4625,7 @@ var Swiper = (function () {
4268
4625
  slidesEl: swiper.isElement && !el.parentNode.host.slideSlots ? el.parentNode.host : wrapperEl,
4269
4626
  hostEl: swiper.isElement ? el.parentNode.host : el,
4270
4627
  mounted: true,
4628
+ // RTL
4271
4629
  rtl: el.dir.toLowerCase() === 'rtl' || elementStyle(el, 'direction') === 'rtl',
4272
4630
  rtlTranslate: swiper.params.direction === 'horizontal' && (el.dir.toLowerCase() === 'rtl' || elementStyle(el, 'direction') === 'rtl'),
4273
4631
  wrongRTL: elementStyle(wrapperEl, 'display') === '-webkit-box'
@@ -4287,6 +4645,7 @@ var Swiper = (function () {
4287
4645
  const gap = Math.abs(swiper.snapGrid[1] - swiper.snapGrid[0]);
4288
4646
  const swiperTranslate = structuredClone(swiper.snapGrid[1]);
4289
4647
  if (isFirstSlide) {
4648
+ // Move last item to first position when at first slide
4290
4649
  const lastSlide = slides.at(-1);
4291
4650
  lastSlide.swiperLoopMoveDOM = true;
4292
4651
  swiper.slidesEl.prepend(lastSlide);
@@ -4298,6 +4657,7 @@ var Swiper = (function () {
4298
4657
  swiper.setTransition(speed);
4299
4658
  swiper.setTranslate(-swiperTranslate);
4300
4659
  } else if (isLastSlide) {
4660
+ // Move first item to last position when at last slide
4301
4661
  const firstSlide = slides[0];
4302
4662
  firstSlide.swiperLoopMoveDOM = true;
4303
4663
  swiper.slidesEl.append(firstSlide);
@@ -4318,24 +4678,42 @@ var Swiper = (function () {
4318
4678
  const mounted = swiper.mount(el);
4319
4679
  if (mounted === false) return swiper;
4320
4680
  swiper.emit('beforeInit');
4681
+
4682
+ // Set breakpoint
4321
4683
  if (swiper.params.breakpoints) {
4322
4684
  swiper.setBreakpoint();
4323
4685
  }
4686
+
4687
+ // Add Classes
4324
4688
  swiper.addClasses();
4689
+
4690
+ // Update size
4325
4691
  swiper.updateSize();
4692
+
4693
+ // Update slides
4326
4694
  swiper.updateSlides();
4327
4695
  if (swiper.params.watchOverflow) {
4328
4696
  swiper.checkOverflow();
4329
4697
  }
4698
+
4699
+ // Set Grab Cursor
4330
4700
  if (swiper.params.grabCursor && swiper.enabled) {
4331
4701
  swiper.setGrabCursor();
4332
4702
  }
4333
4703
 
4334
- // Slide to initial slide (core-lite: no optional feature initial offsets)
4335
- swiper.slideTo(swiper.params.initialSlide, 0, swiper.params.runCallbacksOnInit, false, true);
4704
+ // Slide To Initial Slide
4705
+ if (swiper.params.loop && swiper.virtual && swiper.params.virtual.enabled) {
4706
+ swiper.slideTo(swiper.params.initialSlide + swiper.virtual.slidesBefore, 0, swiper.params.runCallbacksOnInit, false, true);
4707
+ } else {
4708
+ swiper.slideTo(swiper.params.initialSlide, 0, swiper.params.runCallbacksOnInit, false, true);
4709
+ }
4710
+
4711
+ // Create loop
4336
4712
  if (swiper.params.loop) {
4337
4713
  swiper.loopCreate(undefined, true);
4338
4714
  }
4715
+
4716
+ // Attach events
4339
4717
  swiper.attachEvents();
4340
4718
  const lazyElements = [...swiper.el.querySelectorAll('[loading="lazy"]')];
4341
4719
  if (swiper.isElement) {
@@ -4345,12 +4723,18 @@ var Swiper = (function () {
4345
4723
  if (imageEl.complete) {
4346
4724
  processLazyPreloader(swiper, imageEl);
4347
4725
  } else {
4348
- imageEl.addEventListener('load', e => processLazyPreloader(swiper, e.target));
4726
+ imageEl.addEventListener('load', e => {
4727
+ processLazyPreloader(swiper, e.target);
4728
+ });
4349
4729
  }
4350
4730
  });
4351
4731
  preload(swiper);
4732
+
4733
+ // Init Flag
4352
4734
  swiper.initialized = true;
4353
4735
  preload(swiper);
4736
+
4737
+ // Emit
4354
4738
  swiper.emit('init');
4355
4739
  swiper.emit('afterInit');
4356
4740
  return swiper;
@@ -4373,15 +4757,27 @@ var Swiper = (function () {
4373
4757
  return null;
4374
4758
  }
4375
4759
  swiper.emit('beforeDestroy');
4760
+
4761
+ // Init Flag
4376
4762
  swiper.initialized = false;
4763
+
4764
+ // Detach events
4377
4765
  swiper.detachEvents();
4766
+
4767
+ // Destroy loop
4378
4768
  if (params.loop) {
4379
4769
  swiper.loopDestroy();
4380
4770
  }
4771
+
4772
+ // Cleanup styles
4381
4773
  if (cleanStyles) {
4382
4774
  swiper.removeClasses();
4383
- if (el && typeof el !== 'string') el.removeAttribute('style');
4384
- if (wrapperEl) wrapperEl.removeAttribute('style');
4775
+ if (el && typeof el !== 'string') {
4776
+ el.removeAttribute('style');
4777
+ }
4778
+ if (wrapperEl) {
4779
+ wrapperEl.removeAttribute('style');
4780
+ }
4385
4781
  if (slides && slides.length) {
4386
4782
  slides.forEach(slideEl => {
4387
4783
  slideEl.classList.remove(params.slideVisibleClass, params.slideFullyVisibleClass, params.slideActiveClass, params.slideNextClass, params.slidePrevClass);
@@ -4391,6 +4787,8 @@ var Swiper = (function () {
4391
4787
  }
4392
4788
  }
4393
4789
  swiper.emit('destroy');
4790
+
4791
+ // Detach emitter events
4394
4792
  Object.keys(swiper.eventsListeners).forEach(eventName => {
4395
4793
  swiper.off(eventName);
4396
4794
  });
@@ -9825,7 +10223,7 @@ var Swiper = (function () {
9825
10223
  }
9826
10224
 
9827
10225
  /**
9828
- * Swiper 0.0.15-dev.1
10226
+ * Swiper 0.0.15
9829
10227
  * Gem SDK - Swiper, Customized of swiper
9830
10228
  * https://swiperjs.com
9831
10229
  *