text: import $ from '../../utils/dom';
  import Utils from '../../utils/utils';
  
  const Virtual = {
    update(force) {
      const swiper = this;
      const { slidesPerView, slidesPerGroup, centeredSlides } = swiper.params;
      const {
        from: previousFrom,
        to: previousTo,
        slides,
        slidesGrid: previousSlidesGrid,
        renderSlide,
        offset: previousOffset,
      } = swiper.virtual;
      swiper.updateActiveIndex();
      const activeIndex = swiper.activeIndex || 0;
  
      let offsetProp;
      if (swiper.rtl && swiper.isHorizontal()) offsetProp = 'right';
      else offsetProp = swiper.isHorizontal() ? 'left' : 'top';
  
      let slidesAfter;
      let slidesBefore;
      if (centeredSlides) {
        slidesAfter = Math.floor(slidesPerView / 2) + slidesPerGroup;
        slidesBefore = Math.floor(slidesPerView / 2) + slidesPerGroup;
      } else {
        slidesAfter = slidesPerView + (slidesPerGroup - 1);
        slidesBefore = slidesPerGroup;
      }
      const from = Math.max((activeIndex || 0) - slidesBefore, 0);
      const to = Math.min((activeIndex || 0) + slidesAfter, slides.length - 1);
      const offset = (swiper.slidesGrid[from] || 0) - (swiper.slidesGrid[0] || 0);
  
      Utils.extend(swiper.virtual, {
        from,
        to,
        offset,
        slidesGrid: swiper.slidesGrid,
      });
  
      function onRendered() {
        swiper.updateSlides();
        swiper.updateProgress();
        swiper.updateSlidesClasses();
        if (swiper.lazy && swiper.params.lazy.enabled) {
          swiper.lazy.load();
        }
      }
  
      if (previousFrom === from && previousTo === to && !force) {
        if (swiper.slidesGrid !== previousSlidesGrid && offset !== previousOffset) {
          swiper.slides.css(offsetProp, `${offset}px`);
        }
        swiper.updateProgress();
        return;
      }
      if (swiper.params.virtual.renderExternal) {
        swiper.params.virtual.renderExternal.call(swiper, {
          offset,
          from,
          to,
          slides: (function getSlides() {
            const slidesToRender = [];
            for (let i = from; i <= to; i += 1) {
              slidesToRender.push(slides[i]);
            }
            return slidesToRender;
          }()),
        });
        onRendered();
        return;
      }
      const prependIndexes = [];
      const appendIndexes = [];
      if (force) {
        swiper.$wrapperEl.find(`.${swiper.params.slideClass}`).remove();
      } else {
        for (let i = previousFrom; i <= previousTo; i += 1) {
          if (i < from || i > to) {
            swiper.$wrapperEl.find(`.${swiper.params.slideClass}[data-swiper-slide-index="${i}"]`).remove();
          }
        }
      }
      for (let i = 0; i < slides.length; i += 1) {
        if (i >= from && i <= to) {
          if (typeof previousTo === 'undefined' || force) {
            appendIndexes.push(i);
          } else {
            if (i > previousTo) appendIndexes.push(i);
            if (i < previousFrom) prependIndexes.push(i);
          }
        }
      }
      appendIndexes.forEach((index) => {
        swiper.$wrapperEl.append(renderSlide(slides[index], index));
      });
      prependIndexes.sort((a, b) => a < b).forEach((index) => {
        swiper.$wrapperEl.prepend(renderSlide(slides[index], index));
      });
      swiper.$wrapperEl.children('.swiper-slide').css(offsetProp, `${offset}px`);
      onRendered();
    },
    renderSlide(slide, index) {
      const swiper = this;
      const params = swiper.params.virtual;
      if (params.cache && swiper.virtual.cache[index]) {
        return swiper.virtual.cache[index];
      }
      const $slideEl = params.renderSlide
        ? $(params.renderSlide.call(swiper, slide, index))
        : $(`<div class="${swiper.params.slideClass}" data-swiper-slide-index="${index}">${slide}</div>`);
  
      if (params.cache) swiper.virtual.cache[index] = $slideEl;
      return $slideEl;
    },
    appendSlide(slide) {
      const swiper = this;
      swiper.virtual.slides.push(slide);
      swiper.virtual.update(true);
    },
    prependSlide(slide) {
      const swiper = this;
      swiper.virtual.slides.unshift(slide);
      if (swiper.params.virtual.cache) {
        const cache = swiper.virtual.cache;
        const newCache = {};
        Object.keys(cache).forEach((cachedIndex) => {
          newCache[cachedIndex + 1] = cache[cachedIndex];
        });
        swiper.virtual.cache = newCache;
      }
      swiper.virtual.update(true);
      swiper.slideNext(0);
    },
  };
  
  export default {
    name: 'virtual',
    params: {
      virtual: {
        enabled: false,
        slides: [],
        cache: true,
        renderSlide: null,
        renderExternal: null,
      },
    },
    create() {
      const swiper = this;
      Utils.extend(swiper, {
        virtual: {
          update: Virtual.update.bind(swiper),
          appendSlide: Virtual.appendSlide.bind(swiper),
          prependSlide: Virtual.prependSlide.bind(swiper),
          renderSlide: Virtual.renderSlide.bind(swiper),
          slides: swiper.params.virtual.slides,
          cache: {},
        },
      });
    },
    on: {
      beforeInit() {
        const swiper = this;
        if (!swiper.params.virtual.enabled) return;
        swiper.classNames.push(`${swiper.params.containerModifierClass}virtual`);
        Utils.extend(swiper.params, {
          watchSlidesProgress: true,
        });
        swiper.virtual.update();
      },
      setTranslate() {
        const swiper = this;
        if (!swiper.params.virtual.enabled) return;
        swiper.virtual.update();
      },
    },
  };
  