348 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
			
		
		
	
	
			348 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
import { getDocument } from 'ssr-window';
 | 
						|
import { createElement, elementOffset, nextTick } from '../../shared/utils.js';
 | 
						|
import createElementIfNotDefined from '../../shared/create-element-if-not-defined.js';
 | 
						|
export default function Scrollbar({
 | 
						|
  swiper,
 | 
						|
  extendParams,
 | 
						|
  on,
 | 
						|
  emit
 | 
						|
}) {
 | 
						|
  const document = getDocument();
 | 
						|
  let isTouched = false;
 | 
						|
  let timeout = null;
 | 
						|
  let dragTimeout = null;
 | 
						|
  let dragStartPos;
 | 
						|
  let dragSize;
 | 
						|
  let trackSize;
 | 
						|
  let divider;
 | 
						|
  extendParams({
 | 
						|
    scrollbar: {
 | 
						|
      el: null,
 | 
						|
      dragSize: 'auto',
 | 
						|
      hide: false,
 | 
						|
      draggable: false,
 | 
						|
      snapOnRelease: true,
 | 
						|
      lockClass: 'swiper-scrollbar-lock',
 | 
						|
      dragClass: 'swiper-scrollbar-drag',
 | 
						|
      scrollbarDisabledClass: 'swiper-scrollbar-disabled',
 | 
						|
      horizontalClass: `swiper-scrollbar-horizontal`,
 | 
						|
      verticalClass: `swiper-scrollbar-vertical`
 | 
						|
    }
 | 
						|
  });
 | 
						|
  swiper.scrollbar = {
 | 
						|
    el: null,
 | 
						|
    dragEl: null
 | 
						|
  };
 | 
						|
  function setTranslate() {
 | 
						|
    if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
 | 
						|
    const {
 | 
						|
      scrollbar,
 | 
						|
      rtlTranslate: rtl
 | 
						|
    } = swiper;
 | 
						|
    const {
 | 
						|
      dragEl,
 | 
						|
      el
 | 
						|
    } = scrollbar;
 | 
						|
    const params = swiper.params.scrollbar;
 | 
						|
    const progress = swiper.params.loop ? swiper.progressLoop : swiper.progress;
 | 
						|
    let newSize = dragSize;
 | 
						|
    let newPos = (trackSize - dragSize) * progress;
 | 
						|
    if (rtl) {
 | 
						|
      newPos = -newPos;
 | 
						|
      if (newPos > 0) {
 | 
						|
        newSize = dragSize - newPos;
 | 
						|
        newPos = 0;
 | 
						|
      } else if (-newPos + dragSize > trackSize) {
 | 
						|
        newSize = trackSize + newPos;
 | 
						|
      }
 | 
						|
    } else if (newPos < 0) {
 | 
						|
      newSize = dragSize + newPos;
 | 
						|
      newPos = 0;
 | 
						|
    } else if (newPos + dragSize > trackSize) {
 | 
						|
      newSize = trackSize - newPos;
 | 
						|
    }
 | 
						|
    if (swiper.isHorizontal()) {
 | 
						|
      dragEl.style.transform = `translate3d(${newPos}px, 0, 0)`;
 | 
						|
      dragEl.style.width = `${newSize}px`;
 | 
						|
    } else {
 | 
						|
      dragEl.style.transform = `translate3d(0px, ${newPos}px, 0)`;
 | 
						|
      dragEl.style.height = `${newSize}px`;
 | 
						|
    }
 | 
						|
    if (params.hide) {
 | 
						|
      clearTimeout(timeout);
 | 
						|
      el.style.opacity = 1;
 | 
						|
      timeout = setTimeout(() => {
 | 
						|
        el.style.opacity = 0;
 | 
						|
        el.style.transitionDuration = '400ms';
 | 
						|
      }, 1000);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  function setTransition(duration) {
 | 
						|
    if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
 | 
						|
    swiper.scrollbar.dragEl.style.transitionDuration = `${duration}ms`;
 | 
						|
  }
 | 
						|
  function updateSize() {
 | 
						|
    if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
 | 
						|
    const {
 | 
						|
      scrollbar
 | 
						|
    } = swiper;
 | 
						|
    const {
 | 
						|
      dragEl,
 | 
						|
      el
 | 
						|
    } = scrollbar;
 | 
						|
    dragEl.style.width = '';
 | 
						|
    dragEl.style.height = '';
 | 
						|
    trackSize = swiper.isHorizontal() ? el.offsetWidth : el.offsetHeight;
 | 
						|
    divider = swiper.size / (swiper.virtualSize + swiper.params.slidesOffsetBefore - (swiper.params.centeredSlides ? swiper.snapGrid[0] : 0));
 | 
						|
    if (swiper.params.scrollbar.dragSize === 'auto') {
 | 
						|
      dragSize = trackSize * divider;
 | 
						|
    } else {
 | 
						|
      dragSize = parseInt(swiper.params.scrollbar.dragSize, 10);
 | 
						|
    }
 | 
						|
    if (swiper.isHorizontal()) {
 | 
						|
      dragEl.style.width = `${dragSize}px`;
 | 
						|
    } else {
 | 
						|
      dragEl.style.height = `${dragSize}px`;
 | 
						|
    }
 | 
						|
    if (divider >= 1) {
 | 
						|
      el.style.display = 'none';
 | 
						|
    } else {
 | 
						|
      el.style.display = '';
 | 
						|
    }
 | 
						|
    if (swiper.params.scrollbar.hide) {
 | 
						|
      el.style.opacity = 0;
 | 
						|
    }
 | 
						|
    if (swiper.params.watchOverflow && swiper.enabled) {
 | 
						|
      scrollbar.el.classList[swiper.isLocked ? 'add' : 'remove'](swiper.params.scrollbar.lockClass);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  function getPointerPosition(e) {
 | 
						|
    return swiper.isHorizontal() ? e.clientX : e.clientY;
 | 
						|
  }
 | 
						|
  function setDragPosition(e) {
 | 
						|
    const {
 | 
						|
      scrollbar,
 | 
						|
      rtlTranslate: rtl
 | 
						|
    } = swiper;
 | 
						|
    const {
 | 
						|
      el
 | 
						|
    } = scrollbar;
 | 
						|
    let positionRatio;
 | 
						|
    positionRatio = (getPointerPosition(e) - elementOffset(el)[swiper.isHorizontal() ? 'left' : 'top'] - (dragStartPos !== null ? dragStartPos : dragSize / 2)) / (trackSize - dragSize);
 | 
						|
    positionRatio = Math.max(Math.min(positionRatio, 1), 0);
 | 
						|
    if (rtl) {
 | 
						|
      positionRatio = 1 - positionRatio;
 | 
						|
    }
 | 
						|
    const position = swiper.minTranslate() + (swiper.maxTranslate() - swiper.minTranslate()) * positionRatio;
 | 
						|
    swiper.updateProgress(position);
 | 
						|
    swiper.setTranslate(position);
 | 
						|
    swiper.updateActiveIndex();
 | 
						|
    swiper.updateSlidesClasses();
 | 
						|
  }
 | 
						|
  function onDragStart(e) {
 | 
						|
    const params = swiper.params.scrollbar;
 | 
						|
    const {
 | 
						|
      scrollbar,
 | 
						|
      wrapperEl
 | 
						|
    } = swiper;
 | 
						|
    const {
 | 
						|
      el,
 | 
						|
      dragEl
 | 
						|
    } = scrollbar;
 | 
						|
    isTouched = true;
 | 
						|
    dragStartPos = e.target === dragEl ? getPointerPosition(e) - e.target.getBoundingClientRect()[swiper.isHorizontal() ? 'left' : 'top'] : null;
 | 
						|
    e.preventDefault();
 | 
						|
    e.stopPropagation();
 | 
						|
    wrapperEl.style.transitionDuration = '100ms';
 | 
						|
    dragEl.style.transitionDuration = '100ms';
 | 
						|
    setDragPosition(e);
 | 
						|
    clearTimeout(dragTimeout);
 | 
						|
    el.style.transitionDuration = '0ms';
 | 
						|
    if (params.hide) {
 | 
						|
      el.style.opacity = 1;
 | 
						|
    }
 | 
						|
    if (swiper.params.cssMode) {
 | 
						|
      swiper.wrapperEl.style['scroll-snap-type'] = 'none';
 | 
						|
    }
 | 
						|
    emit('scrollbarDragStart', e);
 | 
						|
  }
 | 
						|
  function onDragMove(e) {
 | 
						|
    const {
 | 
						|
      scrollbar,
 | 
						|
      wrapperEl
 | 
						|
    } = swiper;
 | 
						|
    const {
 | 
						|
      el,
 | 
						|
      dragEl
 | 
						|
    } = scrollbar;
 | 
						|
    if (!isTouched) return;
 | 
						|
    if (e.preventDefault) e.preventDefault();else e.returnValue = false;
 | 
						|
    setDragPosition(e);
 | 
						|
    wrapperEl.style.transitionDuration = '0ms';
 | 
						|
    el.style.transitionDuration = '0ms';
 | 
						|
    dragEl.style.transitionDuration = '0ms';
 | 
						|
    emit('scrollbarDragMove', e);
 | 
						|
  }
 | 
						|
  function onDragEnd(e) {
 | 
						|
    const params = swiper.params.scrollbar;
 | 
						|
    const {
 | 
						|
      scrollbar,
 | 
						|
      wrapperEl
 | 
						|
    } = swiper;
 | 
						|
    const {
 | 
						|
      el
 | 
						|
    } = scrollbar;
 | 
						|
    if (!isTouched) return;
 | 
						|
    isTouched = false;
 | 
						|
    if (swiper.params.cssMode) {
 | 
						|
      swiper.wrapperEl.style['scroll-snap-type'] = '';
 | 
						|
      wrapperEl.style.transitionDuration = '';
 | 
						|
    }
 | 
						|
    if (params.hide) {
 | 
						|
      clearTimeout(dragTimeout);
 | 
						|
      dragTimeout = nextTick(() => {
 | 
						|
        el.style.opacity = 0;
 | 
						|
        el.style.transitionDuration = '400ms';
 | 
						|
      }, 1000);
 | 
						|
    }
 | 
						|
    emit('scrollbarDragEnd', e);
 | 
						|
    if (params.snapOnRelease) {
 | 
						|
      swiper.slideToClosest();
 | 
						|
    }
 | 
						|
  }
 | 
						|
  function events(method) {
 | 
						|
    const {
 | 
						|
      scrollbar,
 | 
						|
      params
 | 
						|
    } = swiper;
 | 
						|
    const el = scrollbar.el;
 | 
						|
    if (!el) return;
 | 
						|
    const target = el;
 | 
						|
    const activeListener = params.passiveListeners ? {
 | 
						|
      passive: false,
 | 
						|
      capture: false
 | 
						|
    } : false;
 | 
						|
    const passiveListener = params.passiveListeners ? {
 | 
						|
      passive: true,
 | 
						|
      capture: false
 | 
						|
    } : false;
 | 
						|
    if (!target) return;
 | 
						|
    const eventMethod = method === 'on' ? 'addEventListener' : 'removeEventListener';
 | 
						|
    target[eventMethod]('pointerdown', onDragStart, activeListener);
 | 
						|
    document[eventMethod]('pointermove', onDragMove, activeListener);
 | 
						|
    document[eventMethod]('pointerup', onDragEnd, passiveListener);
 | 
						|
  }
 | 
						|
  function enableDraggable() {
 | 
						|
    if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
 | 
						|
    events('on');
 | 
						|
  }
 | 
						|
  function disableDraggable() {
 | 
						|
    if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
 | 
						|
    events('off');
 | 
						|
  }
 | 
						|
  function init() {
 | 
						|
    const {
 | 
						|
      scrollbar,
 | 
						|
      el: swiperEl
 | 
						|
    } = swiper;
 | 
						|
    swiper.params.scrollbar = createElementIfNotDefined(swiper, swiper.originalParams.scrollbar, swiper.params.scrollbar, {
 | 
						|
      el: 'swiper-scrollbar'
 | 
						|
    });
 | 
						|
    const params = swiper.params.scrollbar;
 | 
						|
    if (!params.el) return;
 | 
						|
    let el;
 | 
						|
    if (typeof params.el === 'string' && swiper.isElement) {
 | 
						|
      el = swiper.el.shadowRoot.querySelector(params.el);
 | 
						|
    }
 | 
						|
    if (!el && typeof params.el === 'string') {
 | 
						|
      el = document.querySelectorAll(params.el);
 | 
						|
    } else if (!el) {
 | 
						|
      el = params.el;
 | 
						|
    }
 | 
						|
    if (swiper.params.uniqueNavElements && typeof params.el === 'string' && el.length > 1 && swiperEl.querySelectorAll(params.el).length === 1) {
 | 
						|
      el = swiperEl.querySelector(params.el);
 | 
						|
    }
 | 
						|
    if (el.length > 0) el = el[0];
 | 
						|
    el.classList.add(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);
 | 
						|
    let dragEl;
 | 
						|
    if (el) {
 | 
						|
      dragEl = el.querySelector(`.${swiper.params.scrollbar.dragClass}`);
 | 
						|
      if (!dragEl) {
 | 
						|
        dragEl = createElement('div', swiper.params.scrollbar.dragClass);
 | 
						|
        el.append(dragEl);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    Object.assign(scrollbar, {
 | 
						|
      el,
 | 
						|
      dragEl
 | 
						|
    });
 | 
						|
    if (params.draggable) {
 | 
						|
      enableDraggable();
 | 
						|
    }
 | 
						|
    if (el) {
 | 
						|
      el.classList[swiper.enabled ? 'remove' : 'add'](swiper.params.scrollbar.lockClass);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  function destroy() {
 | 
						|
    const params = swiper.params.scrollbar;
 | 
						|
    const el = swiper.scrollbar.el;
 | 
						|
    if (el) {
 | 
						|
      el.classList.remove(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);
 | 
						|
    }
 | 
						|
    disableDraggable();
 | 
						|
  }
 | 
						|
  on('init', () => {
 | 
						|
    if (swiper.params.scrollbar.enabled === false) {
 | 
						|
      // eslint-disable-next-line
 | 
						|
      disable();
 | 
						|
    } else {
 | 
						|
      init();
 | 
						|
      updateSize();
 | 
						|
      setTranslate();
 | 
						|
    }
 | 
						|
  });
 | 
						|
  on('update resize observerUpdate lock unlock', () => {
 | 
						|
    updateSize();
 | 
						|
  });
 | 
						|
  on('setTranslate', () => {
 | 
						|
    setTranslate();
 | 
						|
  });
 | 
						|
  on('setTransition', (_s, duration) => {
 | 
						|
    setTransition(duration);
 | 
						|
  });
 | 
						|
  on('enable disable', () => {
 | 
						|
    const {
 | 
						|
      el
 | 
						|
    } = swiper.scrollbar;
 | 
						|
    if (el) {
 | 
						|
      el.classList[swiper.enabled ? 'remove' : 'add'](swiper.params.scrollbar.lockClass);
 | 
						|
    }
 | 
						|
  });
 | 
						|
  on('destroy', () => {
 | 
						|
    destroy();
 | 
						|
  });
 | 
						|
  const enable = () => {
 | 
						|
    swiper.el.classList.remove(swiper.params.scrollbar.scrollbarDisabledClass);
 | 
						|
    if (swiper.scrollbar.el) {
 | 
						|
      swiper.scrollbar.el.classList.remove(swiper.params.scrollbar.scrollbarDisabledClass);
 | 
						|
    }
 | 
						|
    init();
 | 
						|
    updateSize();
 | 
						|
    setTranslate();
 | 
						|
  };
 | 
						|
  const disable = () => {
 | 
						|
    swiper.el.classList.add(swiper.params.scrollbar.scrollbarDisabledClass);
 | 
						|
    if (swiper.scrollbar.el) {
 | 
						|
      swiper.scrollbar.el.classList.add(swiper.params.scrollbar.scrollbarDisabledClass);
 | 
						|
    }
 | 
						|
    destroy();
 | 
						|
  };
 | 
						|
  Object.assign(swiper.scrollbar, {
 | 
						|
    enable,
 | 
						|
    disable,
 | 
						|
    updateSize,
 | 
						|
    setTranslate,
 | 
						|
    init,
 | 
						|
    destroy
 | 
						|
  });
 | 
						|
} |