فهرست منبع

Improve the drag handling.

NaotoshiFujita 3 سال پیش
والد
کامیت
c8c14971d8

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 1
dist/css/splide-core.min.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/css/splide.min.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/css/themes/splide-default.min.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/css/themes/splide-sea-green.min.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/css/themes/splide-skyblue.min.css


+ 194 - 181
dist/js/splide.cjs.js

@@ -24,6 +24,9 @@ const STATES = {
   DESTROYED
 };
 
+const DEFAULT_EVENT_PRIORITY = 10;
+const DEFAULT_USER_EVENT_PRIORITY = 20;
+
 function empty(array) {
   array.length = 0;
 }
@@ -308,165 +311,6 @@ function uniqueId(prefix) {
   return `${prefix}${pad(ids[prefix] = (ids[prefix] || 0) + 1)}`;
 }
 
-function Options(Splide2, Components2, options) {
-  let initialOptions;
-  let points;
-  let currPoint;
-  function setup() {
-    try {
-      merge(options, JSON.parse(getAttribute(Splide2.root, DATA_ATTRIBUTE)));
-    } catch (e) {
-      assert(false, e.message);
-    }
-    initialOptions = merge({}, options);
-  }
-  function mount() {
-    const { breakpoints } = options;
-    if (breakpoints) {
-      points = Object.keys(breakpoints).sort((n, m) => +n - +m).map((point) => [
-        point,
-        matchMedia(`(${options.mediaQuery || "max"}-width:${point}px)`)
-      ]);
-      addEventListener("resize", observe);
-      observe();
-    }
-  }
-  function destroy(completely) {
-    if (completely) {
-      removeEventListener("resize", observe);
-    }
-  }
-  function observe() {
-    const item = find(points, (item2) => item2[1].matches) || [];
-    if (item[0] !== currPoint) {
-      onMatch(currPoint = item[0]);
-    }
-  }
-  function onMatch(point) {
-    const newOptions = options.breakpoints[point] || initialOptions;
-    if (newOptions.destroy) {
-      Splide2.options = initialOptions;
-      Splide2.destroy(newOptions.destroy === "completely");
-    } else {
-      if (Splide2.state.is(DESTROYED)) {
-        destroy(true);
-        Splide2.mount();
-      }
-      Splide2.options = newOptions;
-    }
-  }
-  return {
-    setup,
-    mount,
-    destroy
-  };
-}
-
-const RTL = "rtl";
-const TTB = "ttb";
-
-const ORIENTATION_MAP = {
-  marginRight: ["marginBottom", "marginLeft"],
-  width: ["height"],
-  autoWidth: ["autoHeight"],
-  fixedWidth: ["fixedHeight"],
-  paddingLeft: ["paddingTop", "paddingRight"],
-  paddingRight: ["paddingBottom", "paddingLeft"],
-  left: ["top", "right"],
-  right: ["bottom", "left"],
-  x: ["y"],
-  X: ["Y"],
-  pageX: ["pageY"],
-  ArrowLeft: ["ArrowUp", "ArrowRight"],
-  ArrowRight: ["ArrowDown", "ArrowLeft"]
-};
-function Direction(Splide2, Components2, options) {
-  function resolve(prop, axisOnly) {
-    const { direction } = options;
-    const index = direction === RTL && !axisOnly ? 1 : direction === TTB ? 0 : -1;
-    return ORIENTATION_MAP[prop][index] || prop;
-  }
-  function orient(value) {
-    return value * (options.direction === RTL ? 1 : -1);
-  }
-  return {
-    resolve,
-    orient
-  };
-}
-
-const CLASS_ROOT = PROJECT_CODE;
-const CLASS_SLIDER = `${PROJECT_CODE}__slider`;
-const CLASS_TRACK = `${PROJECT_CODE}__track`;
-const CLASS_LIST = `${PROJECT_CODE}__list`;
-const CLASS_SLIDE = `${PROJECT_CODE}__slide`;
-const CLASS_CLONE = `${CLASS_SLIDE}--clone`;
-const CLASS_CONTAINER = `${CLASS_SLIDE}__container`;
-const CLASS_ARROWS = `${PROJECT_CODE}__arrows`;
-const CLASS_ARROW = `${PROJECT_CODE}__arrow`;
-const CLASS_ARROW_PREV = `${CLASS_ARROW}--prev`;
-const CLASS_ARROW_NEXT = `${CLASS_ARROW}--next`;
-const CLASS_PAGINATION = `${PROJECT_CODE}__pagination`;
-const CLASS_PAGINATION_PAGE = `${CLASS_PAGINATION}__page`;
-const CLASS_PROGRESS = `${PROJECT_CODE}__progress`;
-const CLASS_PROGRESS_BAR = `${CLASS_PROGRESS}__bar`;
-const CLASS_AUTOPLAY = `${PROJECT_CODE}__autoplay`;
-const CLASS_PLAY = `${PROJECT_CODE}__play`;
-const CLASS_PAUSE = `${PROJECT_CODE}__pause`;
-const CLASS_SPINNER = `${PROJECT_CODE}__spinner`;
-const CLASS_INITIALIZED = "is-initialized";
-const CLASS_ACTIVE = "is-active";
-const CLASS_PREV = "is-prev";
-const CLASS_NEXT = "is-next";
-const CLASS_VISIBLE = "is-visible";
-const CLASS_LOADING = "is-loading";
-const STATUS_CLASSES = [CLASS_ACTIVE, CLASS_VISIBLE, CLASS_PREV, CLASS_NEXT, CLASS_LOADING];
-const CLASSES = {
-  slide: CLASS_SLIDE,
-  clone: CLASS_CLONE,
-  arrows: CLASS_ARROWS,
-  arrow: CLASS_ARROW,
-  prev: CLASS_ARROW_PREV,
-  next: CLASS_ARROW_NEXT,
-  pagination: CLASS_PAGINATION,
-  page: CLASS_PAGINATION_PAGE,
-  spinner: CLASS_SPINNER
-};
-
-const EVENT_MOUNTED = "mounted";
-const EVENT_READY = "ready";
-const EVENT_MOVE = "move";
-const EVENT_MOVED = "moved";
-const EVENT_CLICK = "click";
-const EVENT_ACTIVE = "active";
-const EVENT_INACTIVE = "inactive";
-const EVENT_VISIBLE = "visible";
-const EVENT_HIDDEN = "hidden";
-const EVENT_SLIDE_KEYDOWN = "slide:keydown";
-const EVENT_REFRESH = "refresh";
-const EVENT_UPDATED = "undated";
-const EVENT_RESIZE = "resize";
-const EVENT_RESIZED = "resized";
-const EVENT_DRAG = "drag";
-const EVENT_DRAGGING = "dragging";
-const EVENT_DRAGGED = "dragged";
-const EVENT_SCROLL = "scroll";
-const EVENT_SCROLLED = "scrolled";
-const EVENT_DESTROY = "destroy";
-const EVENT_ARROWS_MOUNTED = "arrows:mounted";
-const EVENT_ARROWS_UPDATED = "arrows:updated";
-const EVENT_PAGINATION_MOUNTED = "pagination:mounted";
-const EVENT_PAGINATION_PAGE = "pagination:page";
-const EVENT_PAGINATION_UPDATED = "pagination:updated";
-const EVENT_NAVIGATION_MOUNTED = "navigation:mounted";
-const EVENT_AUTOPLAY_PLAY = "autoplay:play";
-const EVENT_AUTOPLAY_PLAYING = "autoplay:playing";
-const EVENT_AUTOPLAY_PAUSE = "autoplay:pause";
-const EVENT_LAZYLOAD_LOADED = "lazyload:loaded";
-
-const DEFAULT_EVENT_PRIORITY = 10;
-const DEFAULT_USER_EVENT_PRIORITY = 20;
-
 function EventBus() {
   let handlers = {};
   function on(events, callback, key, priority = DEFAULT_EVENT_PRIORITY) {
@@ -517,6 +361,37 @@ function EventBus() {
   };
 }
 
+const EVENT_MOUNTED = "mounted";
+const EVENT_READY = "ready";
+const EVENT_MOVE = "move";
+const EVENT_MOVED = "moved";
+const EVENT_CLICK = "click";
+const EVENT_ACTIVE = "active";
+const EVENT_INACTIVE = "inactive";
+const EVENT_VISIBLE = "visible";
+const EVENT_HIDDEN = "hidden";
+const EVENT_SLIDE_KEYDOWN = "slide:keydown";
+const EVENT_REFRESH = "refresh";
+const EVENT_UPDATED = "undated";
+const EVENT_RESIZE = "resize";
+const EVENT_RESIZED = "resized";
+const EVENT_DRAG = "drag";
+const EVENT_DRAGGING = "dragging";
+const EVENT_DRAGGED = "dragged";
+const EVENT_SCROLL = "scroll";
+const EVENT_SCROLLED = "scrolled";
+const EVENT_DESTROY = "destroy";
+const EVENT_ARROWS_MOUNTED = "arrows:mounted";
+const EVENT_ARROWS_UPDATED = "arrows:updated";
+const EVENT_PAGINATION_MOUNTED = "pagination:mounted";
+const EVENT_PAGINATION_PAGE = "pagination:page";
+const EVENT_PAGINATION_UPDATED = "pagination:updated";
+const EVENT_NAVIGATION_MOUNTED = "navigation:mounted";
+const EVENT_AUTOPLAY_PLAY = "autoplay:play";
+const EVENT_AUTOPLAY_PLAYING = "autoplay:playing";
+const EVENT_AUTOPLAY_PAUSE = "autoplay:pause";
+const EVENT_LAZYLOAD_LOADED = "lazyload:loaded";
+
 function EventInterface(Splide2) {
   const { event } = Splide2;
   const key = {};
@@ -654,6 +529,132 @@ function Throttle(func, duration) {
   return throttled;
 }
 
+function Options(Splide2, Components2, options) {
+  const throttledObserve = Throttle(observe);
+  let initialOptions;
+  let points;
+  let currPoint;
+  function setup() {
+    try {
+      merge(options, JSON.parse(getAttribute(Splide2.root, DATA_ATTRIBUTE)));
+    } catch (e) {
+      assert(false, e.message);
+    }
+    initialOptions = merge({}, options);
+  }
+  function mount() {
+    const { breakpoints } = options;
+    if (breakpoints) {
+      points = Object.keys(breakpoints).sort((n, m) => +n - +m).map((point) => [
+        point,
+        matchMedia(`(${options.mediaQuery || "max"}-width:${point}px)`)
+      ]);
+      addEventListener("resize", throttledObserve);
+      observe();
+    }
+  }
+  function destroy(completely) {
+    if (completely) {
+      removeEventListener("resize", throttledObserve);
+    }
+  }
+  function observe() {
+    const item = find(points, (item2) => item2[1].matches) || [];
+    if (item[0] !== currPoint) {
+      onMatch(currPoint = item[0]);
+    }
+  }
+  function onMatch(point) {
+    const newOptions = options.breakpoints[point] || initialOptions;
+    if (newOptions.destroy) {
+      Splide2.options = initialOptions;
+      Splide2.destroy(newOptions.destroy === "completely");
+    } else {
+      if (Splide2.state.is(DESTROYED)) {
+        destroy(true);
+        Splide2.mount();
+      }
+      Splide2.options = newOptions;
+    }
+  }
+  return {
+    setup,
+    mount,
+    destroy
+  };
+}
+
+const RTL = "rtl";
+const TTB = "ttb";
+
+const ORIENTATION_MAP = {
+  marginRight: ["marginBottom", "marginLeft"],
+  width: ["height"],
+  autoWidth: ["autoHeight"],
+  fixedWidth: ["fixedHeight"],
+  paddingLeft: ["paddingTop", "paddingRight"],
+  paddingRight: ["paddingBottom", "paddingLeft"],
+  left: ["top", "right"],
+  right: ["bottom", "left"],
+  x: ["y"],
+  X: ["Y"],
+  pageX: ["pageY"],
+  ArrowLeft: ["ArrowUp", "ArrowRight"],
+  ArrowRight: ["ArrowDown", "ArrowLeft"]
+};
+function Direction(Splide2, Components2, options) {
+  function resolve(prop, axisOnly) {
+    const { direction } = options;
+    const index = direction === RTL && !axisOnly ? 1 : direction === TTB ? 0 : -1;
+    return ORIENTATION_MAP[prop][index] || prop;
+  }
+  function orient(value) {
+    return value * (options.direction === RTL ? 1 : -1);
+  }
+  return {
+    resolve,
+    orient
+  };
+}
+
+const CLASS_ROOT = PROJECT_CODE;
+const CLASS_SLIDER = `${PROJECT_CODE}__slider`;
+const CLASS_TRACK = `${PROJECT_CODE}__track`;
+const CLASS_LIST = `${PROJECT_CODE}__list`;
+const CLASS_SLIDE = `${PROJECT_CODE}__slide`;
+const CLASS_CLONE = `${CLASS_SLIDE}--clone`;
+const CLASS_CONTAINER = `${CLASS_SLIDE}__container`;
+const CLASS_ARROWS = `${PROJECT_CODE}__arrows`;
+const CLASS_ARROW = `${PROJECT_CODE}__arrow`;
+const CLASS_ARROW_PREV = `${CLASS_ARROW}--prev`;
+const CLASS_ARROW_NEXT = `${CLASS_ARROW}--next`;
+const CLASS_PAGINATION = `${PROJECT_CODE}__pagination`;
+const CLASS_PAGINATION_PAGE = `${CLASS_PAGINATION}__page`;
+const CLASS_PROGRESS = `${PROJECT_CODE}__progress`;
+const CLASS_PROGRESS_BAR = `${CLASS_PROGRESS}__bar`;
+const CLASS_AUTOPLAY = `${PROJECT_CODE}__autoplay`;
+const CLASS_PLAY = `${PROJECT_CODE}__play`;
+const CLASS_PAUSE = `${PROJECT_CODE}__pause`;
+const CLASS_SPINNER = `${PROJECT_CODE}__spinner`;
+const CLASS_INITIALIZED = "is-initialized";
+const CLASS_ACTIVE = "is-active";
+const CLASS_PREV = "is-prev";
+const CLASS_NEXT = "is-next";
+const CLASS_VISIBLE = "is-visible";
+const CLASS_LOADING = "is-loading";
+const STATUS_CLASSES = [CLASS_ACTIVE, CLASS_VISIBLE, CLASS_PREV, CLASS_NEXT, CLASS_LOADING];
+const CLASSES = {
+  slide: CLASS_SLIDE,
+  clone: CLASS_CLONE,
+  arrows: CLASS_ARROWS,
+  arrow: CLASS_ARROW,
+  prev: CLASS_ARROW_PREV,
+  next: CLASS_ARROW_NEXT,
+  pagination: CLASS_PAGINATION,
+  page: CLASS_PAGINATION_PAGE,
+  spinner: CLASS_SPINNER
+};
+
 function Elements(Splide2, Components2, options) {
   const { on } = EventInterface(Splide2);
   const { root } = Splide2;
@@ -873,7 +874,7 @@ function Slide$1(Splide2, index, slideIndex, slide) {
     const slideRect = rect(slide);
     const left = resolve("left");
     const right = resolve("right");
-    return floor(trackRect[left]) <= slideRect[left] && slideRect[right] <= ceil(trackRect[right]);
+    return floor(trackRect[left]) <= ceil(slideRect[left]) && floor(slideRect[right]) <= ceil(trackRect[right]);
   }
   function isWithin(from, distance) {
     let diff = abs(from - index);
@@ -1177,6 +1178,8 @@ function Layout(Splide2, Components2, options) {
   };
 }
 
+const SNAP_THRESHOLD = 10;
+
 function Move(Splide2, Components2, options) {
   const { on, emit } = EventInterface(Splide2);
   const { slideSize, getPadding, totalSize, listSize, sliderSize } = Components2.Layout;
@@ -1187,7 +1190,7 @@ function Move(Splide2, Components2, options) {
   let currPosition = 0;
   let positionRate = 0;
   function mount() {
-    on([EVENT_RESIZE, EVENT_UPDATED, EVENT_REFRESH], reposition);
+    on([EVENT_RESIZE, EVENT_RESIZED, EVENT_UPDATED, EVENT_REFRESH], reposition, DEFAULT_EVENT_PRIORITY - 1);
   }
   function reposition() {
     if (options.drag !== "free") {
@@ -1198,9 +1201,18 @@ function Move(Splide2, Components2, options) {
       }
       if (isExceededMax(currPosition)) {
         translate(getLimit(true));
+      } else {
+        snap(SNAP_THRESHOLD);
       }
     }
   }
+  function snap(threshold) {
+    const position = getPosition();
+    const index = toIndex(position);
+    if (abs(position - toPosition(index)) < threshold) {
+      jump(index);
+    }
+  }
   function move(dest, index, prev) {
     if (!isBusy()) {
       const position = getPosition();
@@ -1216,7 +1228,6 @@ function Move(Splide2, Components2, options) {
   function onMoved(dest, index, prev, oldPosition) {
     if (looping) {
       jump(index);
-      looping = false;
     }
     waiting = false;
     Splide2.state.set(IDLE);
@@ -1762,34 +1773,34 @@ function Drag(Splide2, Components2, options) {
   function mount() {
     if (options.drag) {
       bind(track, POINTER_DOWN_EVENTS, onPointerDown);
+      bind(track, "click", (e) => {
+        prevent(e, true);
+      });
     }
   }
   function onPointerDown(e) {
     isMouse = e.type === "mousedown";
     target = isMouse ? window : track;
     if (!(isMouse && e.button)) {
-      if (!Move.isBusy()) {
-        bind(target, POINTER_MOVE_EVENTS, onPointerMove);
-        bind(target, POINTER_UP_EVENTS, onPointerUp);
-        Move.cancel();
-        Scroll.cancel();
-        startCoord = getCoord(e);
-      } else {
-        prevent(e);
-      }
+      bind(target, POINTER_MOVE_EVENTS, onPointerMove);
+      bind(target, POINTER_UP_EVENTS, onPointerUp);
+      Move.cancel();
+      Scroll.cancel();
+      startCoord = getCoord(e);
     }
   }
   function onPointerMove(e) {
+    console.log(`${Date.now()}: ${e.cancelable}`);
     if (e.cancelable) {
-      const min2 = options.dragMinThreshold || 15;
+      const min2 = options.dragMinThreshold || 2;
       if (isMouse || abs(getCoord(e) - startCoord) > min2) {
         moving = true;
         onDrag();
       }
       if (moving) {
         onDragging(e);
-        prevent(e, true);
       }
+      prevent(e, true);
     } else {
       onPointerUp(e);
     }
@@ -1833,6 +1844,7 @@ function Drag(Splide2, Components2, options) {
       const destination = computeDestination(velocity);
       if (isFree) {
         Scroll.scroll(destination);
+        console.log(velocity);
       } else {
         go(computeIndex(destination), true);
       }
@@ -1892,14 +1904,7 @@ function Keyboard(Splide2, Components2, options) {
       } else {
         target = window;
       }
-      bind(target, "keydown", (e) => {
-        const key = normalize(e.key);
-        if (key === resolve("ArrowLeft")) {
-          Splide2.go("<");
-        } else if (key === resolve("ArrowRight")) {
-          Splide2.go(">");
-        }
-      });
+      bind(target, "keydown", onKeydown);
     }
   }
   function destroy() {
@@ -1910,6 +1915,14 @@ function Keyboard(Splide2, Components2, options) {
       }
     }
   }
+  function onKeydown(e) {
+    const key = normalize(e.key);
+    if (key === resolve("ArrowLeft")) {
+      Splide2.go("<");
+    } else if (key === resolve("ArrowRight")) {
+      Splide2.go(">");
+    }
+  }
   function normalize(key) {
     return includes(IE_ARROW_KEYS, key) ? `Arrow${key}` : key;
   }

+ 194 - 181
dist/js/splide.esm.js

@@ -20,6 +20,9 @@ const STATES = {
   DESTROYED
 };
 
+const DEFAULT_EVENT_PRIORITY = 10;
+const DEFAULT_USER_EVENT_PRIORITY = 20;
+
 function empty(array) {
   array.length = 0;
 }
@@ -304,165 +307,6 @@ function uniqueId(prefix) {
   return `${prefix}${pad(ids[prefix] = (ids[prefix] || 0) + 1)}`;
 }
 
-function Options(Splide2, Components2, options) {
-  let initialOptions;
-  let points;
-  let currPoint;
-  function setup() {
-    try {
-      merge(options, JSON.parse(getAttribute(Splide2.root, DATA_ATTRIBUTE)));
-    } catch (e) {
-      assert(false, e.message);
-    }
-    initialOptions = merge({}, options);
-  }
-  function mount() {
-    const { breakpoints } = options;
-    if (breakpoints) {
-      points = Object.keys(breakpoints).sort((n, m) => +n - +m).map((point) => [
-        point,
-        matchMedia(`(${options.mediaQuery || "max"}-width:${point}px)`)
-      ]);
-      addEventListener("resize", observe);
-      observe();
-    }
-  }
-  function destroy(completely) {
-    if (completely) {
-      removeEventListener("resize", observe);
-    }
-  }
-  function observe() {
-    const item = find(points, (item2) => item2[1].matches) || [];
-    if (item[0] !== currPoint) {
-      onMatch(currPoint = item[0]);
-    }
-  }
-  function onMatch(point) {
-    const newOptions = options.breakpoints[point] || initialOptions;
-    if (newOptions.destroy) {
-      Splide2.options = initialOptions;
-      Splide2.destroy(newOptions.destroy === "completely");
-    } else {
-      if (Splide2.state.is(DESTROYED)) {
-        destroy(true);
-        Splide2.mount();
-      }
-      Splide2.options = newOptions;
-    }
-  }
-  return {
-    setup,
-    mount,
-    destroy
-  };
-}
-
-const RTL = "rtl";
-const TTB = "ttb";
-
-const ORIENTATION_MAP = {
-  marginRight: ["marginBottom", "marginLeft"],
-  width: ["height"],
-  autoWidth: ["autoHeight"],
-  fixedWidth: ["fixedHeight"],
-  paddingLeft: ["paddingTop", "paddingRight"],
-  paddingRight: ["paddingBottom", "paddingLeft"],
-  left: ["top", "right"],
-  right: ["bottom", "left"],
-  x: ["y"],
-  X: ["Y"],
-  pageX: ["pageY"],
-  ArrowLeft: ["ArrowUp", "ArrowRight"],
-  ArrowRight: ["ArrowDown", "ArrowLeft"]
-};
-function Direction(Splide2, Components2, options) {
-  function resolve(prop, axisOnly) {
-    const { direction } = options;
-    const index = direction === RTL && !axisOnly ? 1 : direction === TTB ? 0 : -1;
-    return ORIENTATION_MAP[prop][index] || prop;
-  }
-  function orient(value) {
-    return value * (options.direction === RTL ? 1 : -1);
-  }
-  return {
-    resolve,
-    orient
-  };
-}
-
-const CLASS_ROOT = PROJECT_CODE;
-const CLASS_SLIDER = `${PROJECT_CODE}__slider`;
-const CLASS_TRACK = `${PROJECT_CODE}__track`;
-const CLASS_LIST = `${PROJECT_CODE}__list`;
-const CLASS_SLIDE = `${PROJECT_CODE}__slide`;
-const CLASS_CLONE = `${CLASS_SLIDE}--clone`;
-const CLASS_CONTAINER = `${CLASS_SLIDE}__container`;
-const CLASS_ARROWS = `${PROJECT_CODE}__arrows`;
-const CLASS_ARROW = `${PROJECT_CODE}__arrow`;
-const CLASS_ARROW_PREV = `${CLASS_ARROW}--prev`;
-const CLASS_ARROW_NEXT = `${CLASS_ARROW}--next`;
-const CLASS_PAGINATION = `${PROJECT_CODE}__pagination`;
-const CLASS_PAGINATION_PAGE = `${CLASS_PAGINATION}__page`;
-const CLASS_PROGRESS = `${PROJECT_CODE}__progress`;
-const CLASS_PROGRESS_BAR = `${CLASS_PROGRESS}__bar`;
-const CLASS_AUTOPLAY = `${PROJECT_CODE}__autoplay`;
-const CLASS_PLAY = `${PROJECT_CODE}__play`;
-const CLASS_PAUSE = `${PROJECT_CODE}__pause`;
-const CLASS_SPINNER = `${PROJECT_CODE}__spinner`;
-const CLASS_INITIALIZED = "is-initialized";
-const CLASS_ACTIVE = "is-active";
-const CLASS_PREV = "is-prev";
-const CLASS_NEXT = "is-next";
-const CLASS_VISIBLE = "is-visible";
-const CLASS_LOADING = "is-loading";
-const STATUS_CLASSES = [CLASS_ACTIVE, CLASS_VISIBLE, CLASS_PREV, CLASS_NEXT, CLASS_LOADING];
-const CLASSES = {
-  slide: CLASS_SLIDE,
-  clone: CLASS_CLONE,
-  arrows: CLASS_ARROWS,
-  arrow: CLASS_ARROW,
-  prev: CLASS_ARROW_PREV,
-  next: CLASS_ARROW_NEXT,
-  pagination: CLASS_PAGINATION,
-  page: CLASS_PAGINATION_PAGE,
-  spinner: CLASS_SPINNER
-};
-
-const EVENT_MOUNTED = "mounted";
-const EVENT_READY = "ready";
-const EVENT_MOVE = "move";
-const EVENT_MOVED = "moved";
-const EVENT_CLICK = "click";
-const EVENT_ACTIVE = "active";
-const EVENT_INACTIVE = "inactive";
-const EVENT_VISIBLE = "visible";
-const EVENT_HIDDEN = "hidden";
-const EVENT_SLIDE_KEYDOWN = "slide:keydown";
-const EVENT_REFRESH = "refresh";
-const EVENT_UPDATED = "undated";
-const EVENT_RESIZE = "resize";
-const EVENT_RESIZED = "resized";
-const EVENT_DRAG = "drag";
-const EVENT_DRAGGING = "dragging";
-const EVENT_DRAGGED = "dragged";
-const EVENT_SCROLL = "scroll";
-const EVENT_SCROLLED = "scrolled";
-const EVENT_DESTROY = "destroy";
-const EVENT_ARROWS_MOUNTED = "arrows:mounted";
-const EVENT_ARROWS_UPDATED = "arrows:updated";
-const EVENT_PAGINATION_MOUNTED = "pagination:mounted";
-const EVENT_PAGINATION_PAGE = "pagination:page";
-const EVENT_PAGINATION_UPDATED = "pagination:updated";
-const EVENT_NAVIGATION_MOUNTED = "navigation:mounted";
-const EVENT_AUTOPLAY_PLAY = "autoplay:play";
-const EVENT_AUTOPLAY_PLAYING = "autoplay:playing";
-const EVENT_AUTOPLAY_PAUSE = "autoplay:pause";
-const EVENT_LAZYLOAD_LOADED = "lazyload:loaded";
-
-const DEFAULT_EVENT_PRIORITY = 10;
-const DEFAULT_USER_EVENT_PRIORITY = 20;
-
 function EventBus() {
   let handlers = {};
   function on(events, callback, key, priority = DEFAULT_EVENT_PRIORITY) {
@@ -513,6 +357,37 @@ function EventBus() {
   };
 }
 
+const EVENT_MOUNTED = "mounted";
+const EVENT_READY = "ready";
+const EVENT_MOVE = "move";
+const EVENT_MOVED = "moved";
+const EVENT_CLICK = "click";
+const EVENT_ACTIVE = "active";
+const EVENT_INACTIVE = "inactive";
+const EVENT_VISIBLE = "visible";
+const EVENT_HIDDEN = "hidden";
+const EVENT_SLIDE_KEYDOWN = "slide:keydown";
+const EVENT_REFRESH = "refresh";
+const EVENT_UPDATED = "undated";
+const EVENT_RESIZE = "resize";
+const EVENT_RESIZED = "resized";
+const EVENT_DRAG = "drag";
+const EVENT_DRAGGING = "dragging";
+const EVENT_DRAGGED = "dragged";
+const EVENT_SCROLL = "scroll";
+const EVENT_SCROLLED = "scrolled";
+const EVENT_DESTROY = "destroy";
+const EVENT_ARROWS_MOUNTED = "arrows:mounted";
+const EVENT_ARROWS_UPDATED = "arrows:updated";
+const EVENT_PAGINATION_MOUNTED = "pagination:mounted";
+const EVENT_PAGINATION_PAGE = "pagination:page";
+const EVENT_PAGINATION_UPDATED = "pagination:updated";
+const EVENT_NAVIGATION_MOUNTED = "navigation:mounted";
+const EVENT_AUTOPLAY_PLAY = "autoplay:play";
+const EVENT_AUTOPLAY_PLAYING = "autoplay:playing";
+const EVENT_AUTOPLAY_PAUSE = "autoplay:pause";
+const EVENT_LAZYLOAD_LOADED = "lazyload:loaded";
+
 function EventInterface(Splide2) {
   const { event } = Splide2;
   const key = {};
@@ -650,6 +525,132 @@ function Throttle(func, duration) {
   return throttled;
 }
 
+function Options(Splide2, Components2, options) {
+  const throttledObserve = Throttle(observe);
+  let initialOptions;
+  let points;
+  let currPoint;
+  function setup() {
+    try {
+      merge(options, JSON.parse(getAttribute(Splide2.root, DATA_ATTRIBUTE)));
+    } catch (e) {
+      assert(false, e.message);
+    }
+    initialOptions = merge({}, options);
+  }
+  function mount() {
+    const { breakpoints } = options;
+    if (breakpoints) {
+      points = Object.keys(breakpoints).sort((n, m) => +n - +m).map((point) => [
+        point,
+        matchMedia(`(${options.mediaQuery || "max"}-width:${point}px)`)
+      ]);
+      addEventListener("resize", throttledObserve);
+      observe();
+    }
+  }
+  function destroy(completely) {
+    if (completely) {
+      removeEventListener("resize", throttledObserve);
+    }
+  }
+  function observe() {
+    const item = find(points, (item2) => item2[1].matches) || [];
+    if (item[0] !== currPoint) {
+      onMatch(currPoint = item[0]);
+    }
+  }
+  function onMatch(point) {
+    const newOptions = options.breakpoints[point] || initialOptions;
+    if (newOptions.destroy) {
+      Splide2.options = initialOptions;
+      Splide2.destroy(newOptions.destroy === "completely");
+    } else {
+      if (Splide2.state.is(DESTROYED)) {
+        destroy(true);
+        Splide2.mount();
+      }
+      Splide2.options = newOptions;
+    }
+  }
+  return {
+    setup,
+    mount,
+    destroy
+  };
+}
+
+const RTL = "rtl";
+const TTB = "ttb";
+
+const ORIENTATION_MAP = {
+  marginRight: ["marginBottom", "marginLeft"],
+  width: ["height"],
+  autoWidth: ["autoHeight"],
+  fixedWidth: ["fixedHeight"],
+  paddingLeft: ["paddingTop", "paddingRight"],
+  paddingRight: ["paddingBottom", "paddingLeft"],
+  left: ["top", "right"],
+  right: ["bottom", "left"],
+  x: ["y"],
+  X: ["Y"],
+  pageX: ["pageY"],
+  ArrowLeft: ["ArrowUp", "ArrowRight"],
+  ArrowRight: ["ArrowDown", "ArrowLeft"]
+};
+function Direction(Splide2, Components2, options) {
+  function resolve(prop, axisOnly) {
+    const { direction } = options;
+    const index = direction === RTL && !axisOnly ? 1 : direction === TTB ? 0 : -1;
+    return ORIENTATION_MAP[prop][index] || prop;
+  }
+  function orient(value) {
+    return value * (options.direction === RTL ? 1 : -1);
+  }
+  return {
+    resolve,
+    orient
+  };
+}
+
+const CLASS_ROOT = PROJECT_CODE;
+const CLASS_SLIDER = `${PROJECT_CODE}__slider`;
+const CLASS_TRACK = `${PROJECT_CODE}__track`;
+const CLASS_LIST = `${PROJECT_CODE}__list`;
+const CLASS_SLIDE = `${PROJECT_CODE}__slide`;
+const CLASS_CLONE = `${CLASS_SLIDE}--clone`;
+const CLASS_CONTAINER = `${CLASS_SLIDE}__container`;
+const CLASS_ARROWS = `${PROJECT_CODE}__arrows`;
+const CLASS_ARROW = `${PROJECT_CODE}__arrow`;
+const CLASS_ARROW_PREV = `${CLASS_ARROW}--prev`;
+const CLASS_ARROW_NEXT = `${CLASS_ARROW}--next`;
+const CLASS_PAGINATION = `${PROJECT_CODE}__pagination`;
+const CLASS_PAGINATION_PAGE = `${CLASS_PAGINATION}__page`;
+const CLASS_PROGRESS = `${PROJECT_CODE}__progress`;
+const CLASS_PROGRESS_BAR = `${CLASS_PROGRESS}__bar`;
+const CLASS_AUTOPLAY = `${PROJECT_CODE}__autoplay`;
+const CLASS_PLAY = `${PROJECT_CODE}__play`;
+const CLASS_PAUSE = `${PROJECT_CODE}__pause`;
+const CLASS_SPINNER = `${PROJECT_CODE}__spinner`;
+const CLASS_INITIALIZED = "is-initialized";
+const CLASS_ACTIVE = "is-active";
+const CLASS_PREV = "is-prev";
+const CLASS_NEXT = "is-next";
+const CLASS_VISIBLE = "is-visible";
+const CLASS_LOADING = "is-loading";
+const STATUS_CLASSES = [CLASS_ACTIVE, CLASS_VISIBLE, CLASS_PREV, CLASS_NEXT, CLASS_LOADING];
+const CLASSES = {
+  slide: CLASS_SLIDE,
+  clone: CLASS_CLONE,
+  arrows: CLASS_ARROWS,
+  arrow: CLASS_ARROW,
+  prev: CLASS_ARROW_PREV,
+  next: CLASS_ARROW_NEXT,
+  pagination: CLASS_PAGINATION,
+  page: CLASS_PAGINATION_PAGE,
+  spinner: CLASS_SPINNER
+};
+
 function Elements(Splide2, Components2, options) {
   const { on } = EventInterface(Splide2);
   const { root } = Splide2;
@@ -869,7 +870,7 @@ function Slide$1(Splide2, index, slideIndex, slide) {
     const slideRect = rect(slide);
     const left = resolve("left");
     const right = resolve("right");
-    return floor(trackRect[left]) <= slideRect[left] && slideRect[right] <= ceil(trackRect[right]);
+    return floor(trackRect[left]) <= ceil(slideRect[left]) && floor(slideRect[right]) <= ceil(trackRect[right]);
   }
   function isWithin(from, distance) {
     let diff = abs(from - index);
@@ -1173,6 +1174,8 @@ function Layout(Splide2, Components2, options) {
   };
 }
 
+const SNAP_THRESHOLD = 10;
+
 function Move(Splide2, Components2, options) {
   const { on, emit } = EventInterface(Splide2);
   const { slideSize, getPadding, totalSize, listSize, sliderSize } = Components2.Layout;
@@ -1183,7 +1186,7 @@ function Move(Splide2, Components2, options) {
   let currPosition = 0;
   let positionRate = 0;
   function mount() {
-    on([EVENT_RESIZE, EVENT_UPDATED, EVENT_REFRESH], reposition);
+    on([EVENT_RESIZE, EVENT_RESIZED, EVENT_UPDATED, EVENT_REFRESH], reposition, DEFAULT_EVENT_PRIORITY - 1);
   }
   function reposition() {
     if (options.drag !== "free") {
@@ -1194,9 +1197,18 @@ function Move(Splide2, Components2, options) {
       }
       if (isExceededMax(currPosition)) {
         translate(getLimit(true));
+      } else {
+        snap(SNAP_THRESHOLD);
       }
     }
   }
+  function snap(threshold) {
+    const position = getPosition();
+    const index = toIndex(position);
+    if (abs(position - toPosition(index)) < threshold) {
+      jump(index);
+    }
+  }
   function move(dest, index, prev) {
     if (!isBusy()) {
       const position = getPosition();
@@ -1212,7 +1224,6 @@ function Move(Splide2, Components2, options) {
   function onMoved(dest, index, prev, oldPosition) {
     if (looping) {
       jump(index);
-      looping = false;
     }
     waiting = false;
     Splide2.state.set(IDLE);
@@ -1758,34 +1769,34 @@ function Drag(Splide2, Components2, options) {
   function mount() {
     if (options.drag) {
       bind(track, POINTER_DOWN_EVENTS, onPointerDown);
+      bind(track, "click", (e) => {
+        prevent(e, true);
+      });
     }
   }
   function onPointerDown(e) {
     isMouse = e.type === "mousedown";
     target = isMouse ? window : track;
     if (!(isMouse && e.button)) {
-      if (!Move.isBusy()) {
-        bind(target, POINTER_MOVE_EVENTS, onPointerMove);
-        bind(target, POINTER_UP_EVENTS, onPointerUp);
-        Move.cancel();
-        Scroll.cancel();
-        startCoord = getCoord(e);
-      } else {
-        prevent(e);
-      }
+      bind(target, POINTER_MOVE_EVENTS, onPointerMove);
+      bind(target, POINTER_UP_EVENTS, onPointerUp);
+      Move.cancel();
+      Scroll.cancel();
+      startCoord = getCoord(e);
     }
   }
   function onPointerMove(e) {
+    console.log(`${Date.now()}: ${e.cancelable}`);
     if (e.cancelable) {
-      const min2 = options.dragMinThreshold || 15;
+      const min2 = options.dragMinThreshold || 2;
       if (isMouse || abs(getCoord(e) - startCoord) > min2) {
         moving = true;
         onDrag();
       }
       if (moving) {
         onDragging(e);
-        prevent(e, true);
       }
+      prevent(e, true);
     } else {
       onPointerUp(e);
     }
@@ -1829,6 +1840,7 @@ function Drag(Splide2, Components2, options) {
       const destination = computeDestination(velocity);
       if (isFree) {
         Scroll.scroll(destination);
+        console.log(velocity);
       } else {
         go(computeIndex(destination), true);
       }
@@ -1888,14 +1900,7 @@ function Keyboard(Splide2, Components2, options) {
       } else {
         target = window;
       }
-      bind(target, "keydown", (e) => {
-        const key = normalize(e.key);
-        if (key === resolve("ArrowLeft")) {
-          Splide2.go("<");
-        } else if (key === resolve("ArrowRight")) {
-          Splide2.go(">");
-        }
-      });
+      bind(target, "keydown", onKeydown);
     }
   }
   function destroy() {
@@ -1906,6 +1911,14 @@ function Keyboard(Splide2, Components2, options) {
       }
     }
   }
+  function onKeydown(e) {
+    const key = normalize(e.key);
+    if (key === resolve("ArrowLeft")) {
+      Splide2.go("<");
+    } else if (key === resolve("ArrowRight")) {
+      Splide2.go(">");
+    }
+  }
   function normalize(key) {
     return includes(IE_ARROW_KEYS, key) ? `Arrow${key}` : key;
   }

+ 301 - 281
dist/js/splide.js

@@ -27,6 +27,8 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     MOVING: MOVING,
     DESTROYED: DESTROYED
   };
+  var DEFAULT_EVENT_PRIORITY = 10;
+  var DEFAULT_USER_EVENT_PRIORITY = 20;
 
   function empty(array) {
     array.length = 0;
@@ -347,179 +349,6 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     return "" + prefix + pad(ids[prefix] = (ids[prefix] || 0) + 1);
   }
 
-  function Options(Splide2, Components2, options) {
-    var initialOptions;
-    var points;
-    var currPoint;
-
-    function setup() {
-      try {
-        merge(options, JSON.parse(getAttribute(Splide2.root, DATA_ATTRIBUTE)));
-      } catch (e) {
-        assert(false, e.message);
-      }
-
-      initialOptions = merge({}, options);
-    }
-
-    function mount() {
-      var breakpoints = options.breakpoints;
-
-      if (breakpoints) {
-        points = Object.keys(breakpoints).sort(function (n, m) {
-          return +n - +m;
-        }).map(function (point) {
-          return [point, matchMedia("(" + (options.mediaQuery || "max") + "-width:" + point + "px)")];
-        });
-        addEventListener("resize", observe);
-        observe();
-      }
-    }
-
-    function destroy(completely) {
-      if (completely) {
-        removeEventListener("resize", observe);
-      }
-    }
-
-    function observe() {
-      var item = find(points, function (item2) {
-        return item2[1].matches;
-      }) || [];
-
-      if (item[0] !== currPoint) {
-        onMatch(currPoint = item[0]);
-      }
-    }
-
-    function onMatch(point) {
-      var newOptions = options.breakpoints[point] || initialOptions;
-
-      if (newOptions.destroy) {
-        Splide2.options = initialOptions;
-        Splide2.destroy(newOptions.destroy === "completely");
-      } else {
-        if (Splide2.state.is(DESTROYED)) {
-          destroy(true);
-          Splide2.mount();
-        }
-
-        Splide2.options = newOptions;
-      }
-    }
-
-    return {
-      setup: setup,
-      mount: mount,
-      destroy: destroy
-    };
-  }
-
-  var RTL = "rtl";
-  var TTB = "ttb";
-  var ORIENTATION_MAP = {
-    marginRight: ["marginBottom", "marginLeft"],
-    width: ["height"],
-    autoWidth: ["autoHeight"],
-    fixedWidth: ["fixedHeight"],
-    paddingLeft: ["paddingTop", "paddingRight"],
-    paddingRight: ["paddingBottom", "paddingLeft"],
-    left: ["top", "right"],
-    right: ["bottom", "left"],
-    x: ["y"],
-    X: ["Y"],
-    pageX: ["pageY"],
-    ArrowLeft: ["ArrowUp", "ArrowRight"],
-    ArrowRight: ["ArrowDown", "ArrowLeft"]
-  };
-
-  function Direction(Splide2, Components2, options) {
-    function resolve(prop, axisOnly) {
-      var direction = options.direction;
-      var index = direction === RTL && !axisOnly ? 1 : direction === TTB ? 0 : -1;
-      return ORIENTATION_MAP[prop][index] || prop;
-    }
-
-    function orient(value) {
-      return value * (options.direction === RTL ? 1 : -1);
-    }
-
-    return {
-      resolve: resolve,
-      orient: orient
-    };
-  }
-
-  var CLASS_ROOT = PROJECT_CODE;
-  var CLASS_SLIDER = PROJECT_CODE + "__slider";
-  var CLASS_TRACK = PROJECT_CODE + "__track";
-  var CLASS_LIST = PROJECT_CODE + "__list";
-  var CLASS_SLIDE = PROJECT_CODE + "__slide";
-  var CLASS_CLONE = CLASS_SLIDE + "--clone";
-  var CLASS_CONTAINER = CLASS_SLIDE + "__container";
-  var CLASS_ARROWS = PROJECT_CODE + "__arrows";
-  var CLASS_ARROW = PROJECT_CODE + "__arrow";
-  var CLASS_ARROW_PREV = CLASS_ARROW + "--prev";
-  var CLASS_ARROW_NEXT = CLASS_ARROW + "--next";
-  var CLASS_PAGINATION = PROJECT_CODE + "__pagination";
-  var CLASS_PAGINATION_PAGE = CLASS_PAGINATION + "__page";
-  var CLASS_PROGRESS = PROJECT_CODE + "__progress";
-  var CLASS_PROGRESS_BAR = CLASS_PROGRESS + "__bar";
-  var CLASS_AUTOPLAY = PROJECT_CODE + "__autoplay";
-  var CLASS_PLAY = PROJECT_CODE + "__play";
-  var CLASS_PAUSE = PROJECT_CODE + "__pause";
-  var CLASS_SPINNER = PROJECT_CODE + "__spinner";
-  var CLASS_INITIALIZED = "is-initialized";
-  var CLASS_ACTIVE = "is-active";
-  var CLASS_PREV = "is-prev";
-  var CLASS_NEXT = "is-next";
-  var CLASS_VISIBLE = "is-visible";
-  var CLASS_LOADING = "is-loading";
-  var STATUS_CLASSES = [CLASS_ACTIVE, CLASS_VISIBLE, CLASS_PREV, CLASS_NEXT, CLASS_LOADING];
-  var CLASSES = {
-    slide: CLASS_SLIDE,
-    clone: CLASS_CLONE,
-    arrows: CLASS_ARROWS,
-    arrow: CLASS_ARROW,
-    prev: CLASS_ARROW_PREV,
-    next: CLASS_ARROW_NEXT,
-    pagination: CLASS_PAGINATION,
-    page: CLASS_PAGINATION_PAGE,
-    spinner: CLASS_SPINNER
-  };
-  var EVENT_MOUNTED = "mounted";
-  var EVENT_READY = "ready";
-  var EVENT_MOVE = "move";
-  var EVENT_MOVED = "moved";
-  var EVENT_CLICK = "click";
-  var EVENT_ACTIVE = "active";
-  var EVENT_INACTIVE = "inactive";
-  var EVENT_VISIBLE = "visible";
-  var EVENT_HIDDEN = "hidden";
-  var EVENT_SLIDE_KEYDOWN = "slide:keydown";
-  var EVENT_REFRESH = "refresh";
-  var EVENT_UPDATED = "undated";
-  var EVENT_RESIZE = "resize";
-  var EVENT_RESIZED = "resized";
-  var EVENT_DRAG = "drag";
-  var EVENT_DRAGGING = "dragging";
-  var EVENT_DRAGGED = "dragged";
-  var EVENT_SCROLL = "scroll";
-  var EVENT_SCROLLED = "scrolled";
-  var EVENT_DESTROY = "destroy";
-  var EVENT_ARROWS_MOUNTED = "arrows:mounted";
-  var EVENT_ARROWS_UPDATED = "arrows:updated";
-  var EVENT_PAGINATION_MOUNTED = "pagination:mounted";
-  var EVENT_PAGINATION_PAGE = "pagination:page";
-  var EVENT_PAGINATION_UPDATED = "pagination:updated";
-  var EVENT_NAVIGATION_MOUNTED = "navigation:mounted";
-  var EVENT_AUTOPLAY_PLAY = "autoplay:play";
-  var EVENT_AUTOPLAY_PLAYING = "autoplay:playing";
-  var EVENT_AUTOPLAY_PAUSE = "autoplay:pause";
-  var EVENT_LAZYLOAD_LOADED = "lazyload:loaded";
-  var DEFAULT_EVENT_PRIORITY = 10;
-  var DEFAULT_USER_EVENT_PRIORITY = 20;
-
   function EventBus() {
     var handlers = {};
 
@@ -584,6 +413,37 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     };
   }
 
+  var EVENT_MOUNTED = "mounted";
+  var EVENT_READY = "ready";
+  var EVENT_MOVE = "move";
+  var EVENT_MOVED = "moved";
+  var EVENT_CLICK = "click";
+  var EVENT_ACTIVE = "active";
+  var EVENT_INACTIVE = "inactive";
+  var EVENT_VISIBLE = "visible";
+  var EVENT_HIDDEN = "hidden";
+  var EVENT_SLIDE_KEYDOWN = "slide:keydown";
+  var EVENT_REFRESH = "refresh";
+  var EVENT_UPDATED = "undated";
+  var EVENT_RESIZE = "resize";
+  var EVENT_RESIZED = "resized";
+  var EVENT_DRAG = "drag";
+  var EVENT_DRAGGING = "dragging";
+  var EVENT_DRAGGED = "dragged";
+  var EVENT_SCROLL = "scroll";
+  var EVENT_SCROLLED = "scrolled";
+  var EVENT_DESTROY = "destroy";
+  var EVENT_ARROWS_MOUNTED = "arrows:mounted";
+  var EVENT_ARROWS_UPDATED = "arrows:updated";
+  var EVENT_PAGINATION_MOUNTED = "pagination:mounted";
+  var EVENT_PAGINATION_PAGE = "pagination:page";
+  var EVENT_PAGINATION_UPDATED = "pagination:updated";
+  var EVENT_NAVIGATION_MOUNTED = "navigation:mounted";
+  var EVENT_AUTOPLAY_PLAY = "autoplay:play";
+  var EVENT_AUTOPLAY_PLAYING = "autoplay:playing";
+  var EVENT_AUTOPLAY_PAUSE = "autoplay:pause";
+  var EVENT_LAZYLOAD_LOADED = "lazyload:loaded";
+
   function EventInterface(Splide2) {
     var event = Splide2.event;
     var key = {};
@@ -755,6 +615,148 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     return throttled;
   }
 
+  function Options(Splide2, Components2, options) {
+    var throttledObserve = Throttle(observe);
+    var initialOptions;
+    var points;
+    var currPoint;
+
+    function setup() {
+      try {
+        merge(options, JSON.parse(getAttribute(Splide2.root, DATA_ATTRIBUTE)));
+      } catch (e) {
+        assert(false, e.message);
+      }
+
+      initialOptions = merge({}, options);
+    }
+
+    function mount() {
+      var breakpoints = options.breakpoints;
+
+      if (breakpoints) {
+        points = Object.keys(breakpoints).sort(function (n, m) {
+          return +n - +m;
+        }).map(function (point) {
+          return [point, matchMedia("(" + (options.mediaQuery || "max") + "-width:" + point + "px)")];
+        });
+        addEventListener("resize", throttledObserve);
+        observe();
+      }
+    }
+
+    function destroy(completely) {
+      if (completely) {
+        removeEventListener("resize", throttledObserve);
+      }
+    }
+
+    function observe() {
+      var item = find(points, function (item2) {
+        return item2[1].matches;
+      }) || [];
+
+      if (item[0] !== currPoint) {
+        onMatch(currPoint = item[0]);
+      }
+    }
+
+    function onMatch(point) {
+      var newOptions = options.breakpoints[point] || initialOptions;
+
+      if (newOptions.destroy) {
+        Splide2.options = initialOptions;
+        Splide2.destroy(newOptions.destroy === "completely");
+      } else {
+        if (Splide2.state.is(DESTROYED)) {
+          destroy(true);
+          Splide2.mount();
+        }
+
+        Splide2.options = newOptions;
+      }
+    }
+
+    return {
+      setup: setup,
+      mount: mount,
+      destroy: destroy
+    };
+  }
+
+  var RTL = "rtl";
+  var TTB = "ttb";
+  var ORIENTATION_MAP = {
+    marginRight: ["marginBottom", "marginLeft"],
+    width: ["height"],
+    autoWidth: ["autoHeight"],
+    fixedWidth: ["fixedHeight"],
+    paddingLeft: ["paddingTop", "paddingRight"],
+    paddingRight: ["paddingBottom", "paddingLeft"],
+    left: ["top", "right"],
+    right: ["bottom", "left"],
+    x: ["y"],
+    X: ["Y"],
+    Y: ["X"],
+    ArrowLeft: ["ArrowUp", "ArrowRight"],
+    ArrowRight: ["ArrowDown", "ArrowLeft"]
+  };
+
+  function Direction(Splide2, Components2, options) {
+    function resolve(prop, axisOnly) {
+      var direction = options.direction;
+      var index = direction === RTL && !axisOnly ? 1 : direction === TTB ? 0 : -1;
+      return ORIENTATION_MAP[prop][index] || prop;
+    }
+
+    function orient(value) {
+      return value * (options.direction === RTL ? 1 : -1);
+    }
+
+    return {
+      resolve: resolve,
+      orient: orient
+    };
+  }
+
+  var CLASS_ROOT = PROJECT_CODE;
+  var CLASS_SLIDER = PROJECT_CODE + "__slider";
+  var CLASS_TRACK = PROJECT_CODE + "__track";
+  var CLASS_LIST = PROJECT_CODE + "__list";
+  var CLASS_SLIDE = PROJECT_CODE + "__slide";
+  var CLASS_CLONE = CLASS_SLIDE + "--clone";
+  var CLASS_CONTAINER = CLASS_SLIDE + "__container";
+  var CLASS_ARROWS = PROJECT_CODE + "__arrows";
+  var CLASS_ARROW = PROJECT_CODE + "__arrow";
+  var CLASS_ARROW_PREV = CLASS_ARROW + "--prev";
+  var CLASS_ARROW_NEXT = CLASS_ARROW + "--next";
+  var CLASS_PAGINATION = PROJECT_CODE + "__pagination";
+  var CLASS_PAGINATION_PAGE = CLASS_PAGINATION + "__page";
+  var CLASS_PROGRESS = PROJECT_CODE + "__progress";
+  var CLASS_PROGRESS_BAR = CLASS_PROGRESS + "__bar";
+  var CLASS_AUTOPLAY = PROJECT_CODE + "__autoplay";
+  var CLASS_PLAY = PROJECT_CODE + "__play";
+  var CLASS_PAUSE = PROJECT_CODE + "__pause";
+  var CLASS_SPINNER = PROJECT_CODE + "__spinner";
+  var CLASS_INITIALIZED = "is-initialized";
+  var CLASS_ACTIVE = "is-active";
+  var CLASS_PREV = "is-prev";
+  var CLASS_NEXT = "is-next";
+  var CLASS_VISIBLE = "is-visible";
+  var CLASS_LOADING = "is-loading";
+  var STATUS_CLASSES = [CLASS_ACTIVE, CLASS_VISIBLE, CLASS_PREV, CLASS_NEXT, CLASS_LOADING];
+  var CLASSES = {
+    slide: CLASS_SLIDE,
+    clone: CLASS_CLONE,
+    arrows: CLASS_ARROWS,
+    arrow: CLASS_ARROW,
+    prev: CLASS_ARROW_PREV,
+    next: CLASS_ARROW_NEXT,
+    pagination: CLASS_PAGINATION,
+    page: CLASS_PAGINATION_PAGE,
+    spinner: CLASS_SPINNER
+  };
+
   function Elements(Splide2, Components2, options) {
     var _EventInterface = EventInterface(Splide2),
         on = _EventInterface.on;
@@ -2116,151 +2118,158 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
   }
 
   var FRICTION = 5;
-  var SAMPLING_INTERVAL = 50;
+  var LOG_INTERVAL = 50;
   var POINTER_DOWN_EVENTS = "touchstart mousedown";
   var POINTER_MOVE_EVENTS = "touchmove mousemove";
   var POINTER_UP_EVENTS = "touchend touchcancel mouseup mouseleave";
 
   function Drag(Splide2, Components2, options) {
     var _EventInterface12 = EventInterface(Splide2),
+        on = _EventInterface12.on,
         emit = _EventInterface12.emit,
         bind = _EventInterface12.bind,
         unbind = _EventInterface12.unbind;
 
+    var Move = Components2.Move,
+        Scroll = Components2.Scroll,
+        Controller = Components2.Controller;
     var track = Components2.Elements.track;
     var _Components2$Directio2 = Components2.Direction,
         resolve = _Components2$Directio2.resolve,
         orient = _Components2$Directio2.orient;
-    var listSize = Components2.Layout.listSize;
-    var _Components2$Controll = Components2.Controller,
-        go = _Components2$Controll.go,
-        getEnd = _Components2$Controll.getEnd;
-    var Move = Components2.Move,
-        Scroll = Components2.Scroll;
-    var translate = Move.translate,
-        toIndex = Move.toIndex,
-        getPosition = Move.getPosition,
+    var getPosition = Move.getPosition,
         isExceeded = Move.isExceeded;
     var isSlide = Splide2.is(SLIDE);
     var isFade = Splide2.is(FADE);
-    var isFree = options.drag === "free";
-    var startCoord;
-    var lastTime;
     var basePosition;
-    var baseCoord;
-    var baseTime;
+    var baseEvent;
+    var prevBaseEvent;
     var lastEvent;
-    var moving;
+    var isFree;
+    var isDragging;
     var isMouse;
+    var hasExceeded = false;
+    var clickPrevented;
+    var disabled;
     var target;
-    var exceeded;
 
     function mount() {
-      if (options.drag) {
-        bind(track, POINTER_DOWN_EVENTS, onPointerDown);
-      }
+      bind(track, POINTER_DOWN_EVENTS, onPointerDown);
+      bind(track, "click", onClick, {
+        capture: true
+      });
+      on([EVENT_MOUNTED, EVENT_UPDATED], init);
     }
 
-    function onPointerDown(e) {
-      isMouse = e.type === "mousedown";
-      target = isMouse ? window : track;
+    function init() {
+      var drag = options.drag;
+      disable(!drag);
+      isFree = drag === "free";
+    }
 
-      if (!(isMouse && e.button)) {
-        if (!Move.isBusy()) {
+    function onPointerDown(e) {
+      if (!disabled) {
+        isMouse = e.type === "mousedown";
+
+        if (!Move.isBusy() && (!isMouse || !e.button)) {
+          target = isMouse ? window : track;
+          prevBaseEvent = null;
+          lastEvent = null;
+          clickPrevented = false;
           bind(target, POINTER_MOVE_EVENTS, onPointerMove);
           bind(target, POINTER_UP_EVENTS, onPointerUp);
           Move.cancel();
           Scroll.cancel();
-          startCoord = getCoord(e);
-        } else {
-          prevent(e);
+          save(e);
         }
       }
     }
 
     function onPointerMove(e) {
-      if (e.cancelable) {
-        var min2 = options.dragMinThreshold || 15;
+      if (!lastEvent) {
+        clickPrevented = true;
+        emit(EVENT_DRAG);
+      }
+
+      lastEvent = e;
+
+      if (!e.cancelable) {
+        return;
+      }
 
-        if (isMouse || abs(getCoord(e) - startCoord) > min2) {
-          moving = true;
-          onDrag();
+      if (isDragging) {
+        var expired = timeOf(e) - timeOf(baseEvent) > LOG_INTERVAL;
+        var exceeded = hasExceeded !== (hasExceeded = isExceeded());
+
+        if (expired || exceeded) {
+          save(e);
         }
 
-        if (moving) {
-          onDragging(e);
-          prevent(e, true);
+        if (!isFade) {
+          Move.translate(basePosition + constrain(coordOf(e) - coordOf(baseEvent)));
         }
+
+        emit(EVENT_DRAGGING);
+        prevent(e);
       } else {
-        onPointerUp(e);
+        var threshold = options.dragMinThreshold || 15;
+        isDragging = isMouse || abs(coordOf(e) - coordOf(baseEvent)) > threshold;
+
+        if (isSliderDirection()) {
+          prevent(e);
+        }
       }
     }
 
     function onPointerUp(e) {
       unbind(target, POINTER_MOVE_EVENTS + " " + POINTER_UP_EVENTS);
-      moving = false;
 
       if (lastEvent) {
-        onDragged(e);
-        lastEvent = null;
-      }
-    }
-
-    function onDrag() {
-      bind(track, "click", function (e) {
-        unbind(track, "click");
-        prevent(e, true);
-      }, {
-        capture: true
-      });
-      emit(EVENT_DRAG);
-    }
-
-    function onDragging(e) {
-      var timeStamp = e.timeStamp;
-      var expired = !lastTime || timeStamp - lastTime > SAMPLING_INTERVAL;
-
-      if (expired || isExceeded() !== exceeded) {
-        basePosition = getPosition();
-        baseCoord = getCoord(e);
-        baseTime = timeStamp;
-      }
+        if (isDragging || e.cancelable && isSliderDirection()) {
+          var velocity = computeVelocity(e);
+          var destination = computeDestination(velocity);
+
+          if (isFree) {
+            Scroll.scroll(destination);
+          } else if (isFade) {
+            Controller.go(Splide2.index + orient(sign(velocity)));
+          } else {
+            Controller.go(computeIndex(destination), true);
+          }
 
-      exceeded = isExceeded();
-      lastTime = timeStamp;
-      lastEvent = e;
+          prevent(e);
+        }
 
-      if (!isFade) {
-        translate(basePosition + constrain(getCoord(e) - baseCoord));
+        emit(EVENT_DRAGGED);
       }
 
-      emit(EVENT_DRAGGING);
+      isDragging = false;
     }
 
-    function onDragged(e) {
-      var velocity = computeVelocity(e);
-
-      if (isFade) {
-        go(Splide2.index + orient(sign(velocity)));
-      } else {
-        var destination = computeDestination(velocity);
+    function save(e) {
+      prevBaseEvent = baseEvent;
+      baseEvent = e;
+      basePosition = getPosition();
+    }
 
-        if (isFree) {
-          Scroll.scroll(destination);
-        } else {
-          go(computeIndex(destination), true);
-        }
+    function onClick(e) {
+      if (!disabled && clickPrevented) {
+        prevent(e, true);
       }
+    }
 
-      lastTime = 0;
-      emit(EVENT_DRAGGED);
+    function isSliderDirection() {
+      var diffX = abs(coordOf(lastEvent) - coordOf(baseEvent));
+      var diffY = abs(coordOf(lastEvent, true) - coordOf(baseEvent, true));
+      return diffX > diffY;
     }
 
     function computeVelocity(e) {
-      if (Splide2.is(LOOP) || !isExceeded()) {
-        var diffCoord = getCoord(lastEvent) - baseCoord;
-        var diffTime = lastEvent.timeStamp - baseTime;
-        var isFlick = e.timeStamp - lastTime < SAMPLING_INTERVAL;
+      if (Splide2.is(LOOP) || !hasExceeded) {
+        var base = baseEvent === lastEvent && prevBaseEvent || baseEvent;
+        var diffCoord = coordOf(lastEvent) - coordOf(base);
+        var diffTime = timeOf(e) - timeOf(base);
+        var isFlick = timeOf(e) - timeOf(lastEvent) < LOG_INTERVAL;
 
         if (diffTime && isFlick) {
           return diffCoord / diffTime;
@@ -2271,25 +2280,34 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
     }
 
     function computeDestination(velocity) {
-      var flickPower = options.flickPower || 600;
-      return getPosition() + sign(velocity) * min(abs(velocity) * flickPower, isFree ? Infinity : listSize() * (options.flickMaxPages || 1));
+      return getPosition() + sign(velocity) * min(abs(velocity) * (options.flickPower || 600), isFree ? Infinity : Components2.Layout.listSize() * (options.flickMaxPages || 1));
     }
 
     function computeIndex(destination) {
-      var dest = toIndex(destination);
-      return isSlide ? clamp(dest, 0, getEnd()) : dest;
+      var dest = Move.toIndex(destination);
+      return isSlide ? clamp(dest, 0, Controller.getEnd()) : dest;
     }
 
-    function getCoord(e) {
-      return (isMouse ? e : e.touches[0])[resolve("pageX")];
+    function coordOf(e, orthogonal) {
+      var prop = "page" + resolve(orthogonal ? "Y" : "X");
+      return (isMouse ? e : e.touches[0])[prop];
+    }
+
+    function timeOf(e) {
+      return e.timeStamp;
     }
 
     function constrain(diff) {
-      return diff / (exceeded && isSlide ? FRICTION : 1);
+      return diff / (hasExceeded && isSlide ? FRICTION : 1);
+    }
+
+    function disable(value) {
+      disabled = value;
     }
 
     return {
-      mount: mount
+      mount: mount,
+      disable: disable
     };
   }
 
@@ -2325,15 +2343,7 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
           target = window;
         }
 
-        bind(target, "keydown", function (e) {
-          var key = normalize(e.key);
-
-          if (key === resolve("ArrowLeft")) {
-            Splide2.go("<");
-          } else if (key === resolve("ArrowRight")) {
-            Splide2.go(">");
-          }
-        });
+        bind(target, "keydown", onKeydown);
       }
     }
 
@@ -2347,6 +2357,16 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
       }
     }
 
+    function onKeydown(e) {
+      var key = normalize(e.key);
+
+      if (key === resolve("ArrowLeft")) {
+        Splide2.go("<");
+      } else if (key === resolve("ArrowRight")) {
+        Splide2.go(">");
+      }
+    }
+
     function normalize(key) {
       return includes(IE_ARROW_KEYS, key) ? "Arrow" + key : key;
     }
@@ -2481,11 +2501,11 @@ function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _d
         unbind = _EventInterface15.unbind;
 
     var Slides = Components2.Slides;
-    var _Components2$Controll2 = Components2.Controller,
-        go = _Components2$Controll2.go,
-        toPage = _Components2$Controll2.toPage,
-        hasFocus = _Components2$Controll2.hasFocus,
-        getIndex = _Components2$Controll2.getIndex;
+    var _Components2$Controll = Components2.Controller,
+        go = _Components2$Controll.go,
+        toPage = _Components2$Controll.toPage,
+        hasFocus = _Components2$Controll.hasFocus,
+        getIndex = _Components2$Controll.getIndex;
     var items = [];
     var list;
 

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/splide.js.map


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
dist/js/splide.min.js


BIN
dist/js/splide.min.js.gz


+ 1 - 1
dist/types/components/Keyboard/Keyboard.d.ts.map

@@ -1 +1 @@
-{"version":3,"file":"Keyboard.d.ts","sourceRoot":"","sources":["Keyboard.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAIjE;;;;GAIG;AACH,MAAM,WAAW,iBAAkB,SAAQ,aAAa;CACvD;AASD;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAI,iBAAiB,CA4EtG"}
+{"version":3,"file":"Keyboard.d.ts","sourceRoot":"","sources":["Keyboard.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAIjE;;;;GAIG;AACH,MAAM,WAAW,iBAAkB,SAAQ,aAAa;CACvD;AASD;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAI,iBAAiB,CAmFtG"}

+ 1 - 1
dist/types/components/Move/Move.d.ts.map

@@ -1 +1 @@
-{"version":3,"file":"Move.d.ts","sourceRoot":"","sources":["Move.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAIjE;;;;GAIG;AACH,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAI,IAAI,CAAC;IACxD,IAAI,CAAE,KAAK,EAAE,MAAM,GAAI,IAAI,CAAC;IAC5B,SAAS,CAAE,QAAQ,EAAE,MAAM,GAAI,IAAI,CAAC;IACpC,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,CAAE,QAAQ,EAAE,MAAM,GAAI,MAAM,CAAC;IACpC,UAAU,CAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAI,MAAM,CAAC;IACxD,WAAW,IAAI,MAAM,CAAC;IACtB,QAAQ,CAAE,GAAG,EAAE,OAAO,GAAI,MAAM,CAAC;IACjC,MAAM,IAAI,OAAO,CAAC;IAClB,UAAU,IAAI,OAAO,CAAC;IACtB,aAAa,CAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAI,OAAO,CAAC;IAC5D,aAAa,CAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAI,OAAO,CAAC;CAC7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAI,aAAa,CAwS9F"}
+{"version":3,"file":"Move.d.ts","sourceRoot":"","sources":["Move.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAKjE;;;;GAIG;AACH,MAAM,WAAW,aAAc,SAAQ,aAAa;IAClD,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAI,IAAI,CAAC;IACxD,IAAI,CAAE,KAAK,EAAE,MAAM,GAAI,IAAI,CAAC;IAC5B,SAAS,CAAE,QAAQ,EAAE,MAAM,GAAI,IAAI,CAAC;IACpC,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,CAAE,QAAQ,EAAE,MAAM,GAAI,MAAM,CAAC;IACpC,UAAU,CAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAI,MAAM,CAAC;IACxD,WAAW,IAAI,MAAM,CAAC;IACtB,QAAQ,CAAE,GAAG,EAAE,OAAO,GAAI,MAAM,CAAC;IACjC,MAAM,IAAI,OAAO,CAAC;IAClB,UAAU,IAAI,OAAO,CAAC;IACtB,aAAa,CAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAI,OAAO,CAAC;IAC5D,aAAa,CAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAI,OAAO,CAAC;CAC7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAI,aAAa,CAwT9F"}

+ 7 - 0
dist/types/components/Move/constants.d.ts

@@ -0,0 +1,7 @@
+/**
+ * The threshold for snapping the slider to the closest slide.
+ *
+ * @since 3.0.0
+ */
+export declare const SNAP_THRESHOLD = 10;
+//# sourceMappingURL=../../../../src/js/components/Move/constants.d.ts.map

+ 1 - 0
dist/types/components/Move/constants.d.ts.map

@@ -0,0 +1 @@
+{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,cAAc,KAAK,CAAC"}

+ 1 - 1
dist/types/components/Options/Options.d.ts.map

@@ -1 +1 @@
-{"version":3,"file":"Options.d.ts","sourceRoot":"","sources":["Options.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAIjE;;;;GAIG;AACH,MAAM,WAAW,gBAAiB,SAAQ,aAAa;CACtD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAI,gBAAgB,CAiGpG"}
+{"version":3,"file":"Options.d.ts","sourceRoot":"","sources":["Options.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAIjE;;;;GAIG;AACH,MAAM,WAAW,gBAAiB,SAAQ,aAAa;CACtD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAI,gBAAgB,CAsGpG"}

+ 1 - 1
dist/types/components/Slides/Slide.d.ts.map

@@ -1 +1 @@
-{"version":3,"file":"Slide.d.ts","sourceRoot":"","sources":["Slide.ts"],"names":[],"mappings":"AAmCA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAmB5C;;;;GAIG;AACH,MAAM,WAAY,cAAe,SAAQ,aAAa;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;IACnB,SAAS,EAAE,WAAW,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,GAAI,IAAI,CAAA;IAC1E,QAAQ,CAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAI,OAAO,CAAC;CACrD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAI,cAAc,CAoM7G"}
+{"version":3,"file":"Slide.d.ts","sourceRoot":"","sources":["Slide.ts"],"names":[],"mappings":"AAiCA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAmB5C;;;;GAIG;AACH,MAAM,WAAY,cAAe,SAAQ,aAAa;IACpD,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,WAAW,CAAC;IACnB,SAAS,EAAE,WAAW,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,YAAY,CAAC,EAAE,OAAO,GAAI,IAAI,CAAA;IAC1E,QAAQ,CAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAI,OAAO,CAAC;CACrD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAI,cAAc,CAqM7G"}

+ 2 - 0
scripts/build-script.js

@@ -46,6 +46,8 @@ function buildScript( compress ) {
         } );
       } );
     }
+  } ).catch( e => {
+    console.error( e );
   } );
 }
 

+ 1 - 1
scripts/develop.js

@@ -3,6 +3,6 @@ const { buildJs } = require( './build-script' );
 
 chokidar.watch( [ './src/js/**/*.ts', '!*.test.ts' ] ).on( 'change', async () => {
   console.log( 'Building...' );
-  await buildJs();
+  await buildJs()
   console.log( 'Finished' );
 } );

+ 10 - 0
src/css/core/object/modifiers/draggable.scss

@@ -0,0 +1,10 @@
+.splide {
+  $root: &;
+
+  &--draggable {
+    > #{ $root }__slider > #{ $root }__track,
+    > #{ $root }__track {
+      user-select: none;
+    }
+  }
+}

+ 1 - 0
src/css/core/object/modifiers/index.scss

@@ -1,3 +1,4 @@
+@forward 'draggable';
 @forward 'fade';
 @forward 'rtl';
 @forward 'ttb';

+ 1 - 1
src/js/components/Direction/Direction.ts

@@ -29,7 +29,7 @@ export const ORIENTATION_MAP = {
   right       : [ 'bottom', 'left' ],
   x           : [ 'y' ],
   X           : [ 'Y' ],
-  pageX       : [ 'pageY' ],
+  Y           : [ 'X' ],
   ArrowLeft   : [ 'ArrowUp', 'ArrowRight' ],
   ArrowRight  : [ 'ArrowDown', 'ArrowLeft' ],
 };

+ 154 - 111
src/js/components/Drag/Drag.ts

@@ -1,10 +1,10 @@
-import { EVENT_DRAG, EVENT_DRAGGED, EVENT_DRAGGING } from '../../constants/events';
+import { EVENT_DRAG, EVENT_DRAGGED, EVENT_DRAGGING, EVENT_MOUNTED, EVENT_UPDATED } from '../../constants/events';
 import { FADE, LOOP, SLIDE } from '../../constants/types';
 import { EventInterface } from '../../constructors';
 import { Splide } from '../../core/Splide/Splide';
 import { BaseComponent, Components, Options } from '../../types';
 import { abs, clamp, min, prevent, sign } from '../../utils';
-import { FRICTION, POINTER_DOWN_EVENTS, POINTER_MOVE_EVENTS, POINTER_UP_EVENTS, SAMPLING_INTERVAL } from './constants';
+import { FRICTION, LOG_INTERVAL, POINTER_DOWN_EVENTS, POINTER_MOVE_EVENTS, POINTER_UP_EVENTS } from './constants';
 
 
 /**
@@ -13,6 +13,7 @@ import { FRICTION, POINTER_DOWN_EVENTS, POINTER_MOVE_EVENTS, POINTER_UP_EVENTS,
  * @since 3.0.0
  */
 export interface DragComponent extends BaseComponent {
+  disable( disabled: boolean ): void
 }
 
 /**
@@ -27,51 +28,43 @@ export interface DragComponent extends BaseComponent {
  * @return A Drag component object.
  */
 export function Drag( Splide: Splide, Components: Components, options: Options ): DragComponent {
-  const { emit, bind, unbind } = EventInterface( Splide );
+  const { on, emit, bind, unbind } = EventInterface( Splide );
+  const { Move, Scroll, Controller } = Components;
   const { track } = Components.Elements;
   const { resolve, orient } = Components.Direction;
-  const { listSize } = Components.Layout;
-  const { go, getEnd } = Components.Controller;
-  const { Move, Scroll } = Components;
-  const { translate, toIndex, getPosition, isExceeded } = Move;
+  const { getPosition, isExceeded } = Move;
   const isSlide = Splide.is( SLIDE );
   const isFade  = Splide.is( FADE );
-  const isFree  = options.drag === 'free';
 
   /**
-   * The coord where a pointer becomes active.
+   * The base slider position to calculate the delta of coords.
    */
-  let startCoord: number;
-
-  /**
-   * Keeps the last time when the component detects dragging.
-   */
-  let lastTime: number;
+  let basePosition: number;
 
   /**
-   * The base slider position where the diff of coords is applied.
+   * The base event object saved per specific sampling interval.
    */
-  let basePosition: number;
+  let baseEvent: TouchEvent | MouseEvent;
 
   /**
-   * The base coord to calculate the diff of coords.
+   * Holds the previous base event object.
    */
-  let baseCoord: number;
+  let prevBaseEvent: TouchEvent | MouseEvent;
 
   /**
-   * The base time when the base position and the base coord are saved.
+   * Keeps the last TouchEvent/MouseEvent object on pointermove.
    */
-  let baseTime: number;
+  let lastEvent: TouchEvent | MouseEvent;
 
   /**
-   * Keeps the last TouchEvent/MouseEvent object.
+   * Indicates whether the drag mode is `free` or not.
    */
-  let lastEvent: TouchEvent | MouseEvent;
+  let isFree: boolean;
 
   /**
    * Indicates whether the user is dragging the slider or not.
    */
-  let moving: boolean;
+  let isDragging: boolean;
 
   /**
    * Indicates whether the user drags the slider by the mouse or not.
@@ -79,42 +72,65 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
   let isMouse: boolean;
 
   /**
-   * The target element to attach listeners.
+   * Indicates whether the slider exceeds limits or not.
+   * This must not be `undefined` for strict comparison.
    */
-  let target: Window | HTMLElement;
+  let hasExceeded = false;
 
   /**
-   * Indicates whether the slider exceeds borders or not.
+   * Turns into `true` when the user starts dragging the slider.
    */
-  let exceeded: boolean;
+  let clickPrevented: boolean;
+
+  /**
+   * Indicates whether the drag component is now disabled or not.
+   */
+  let disabled: boolean;
+
+  /**
+   * The target element to attach listeners.
+   */
+  let target: Window | HTMLElement;
 
   /**
    * Called when the component is mounted.
    */
   function mount(): void {
-    if ( options.drag ) {
-      bind( track, POINTER_DOWN_EVENTS, onPointerDown );
-    }
+    bind( track, POINTER_DOWN_EVENTS, onPointerDown );
+    bind( track, 'click', onClick, { capture: true } );
+    on( [ EVENT_MOUNTED, EVENT_UPDATED ], init );
+  }
+
+  /**
+   * Initializes the component.
+   */
+  function init(): void {
+    const { drag } = options;
+    disable( ! drag );
+    isFree = drag === 'free';
   }
 
   /**
    * Called when the user clicks or touches the slider.
+   * Note that IE does not support MouseEvent and TouchEvent constructors.
    *
    * @param e - A TouchEvent or MouseEvent object
    */
   function onPointerDown( e: TouchEvent | MouseEvent ): void {
-    isMouse = e.type === 'mousedown';
-    target  = isMouse ? window : track;
+    if ( ! disabled ) {
+      isMouse = e.type === 'mousedown';
+
+      if ( ! Move.isBusy() && ( ! isMouse || ! ( e as MouseEvent ).button ) ) {
+        target         = isMouse ? window : track;
+        prevBaseEvent  = null;
+        lastEvent      = null;
+        clickPrevented = false;
 
-    if ( ! ( isMouse && ( e as MouseEvent ).button ) ) {
-      if ( ! Move.isBusy() ) {
         bind( target, POINTER_MOVE_EVENTS, onPointerMove );
         bind( target, POINTER_UP_EVENTS, onPointerUp );
         Move.cancel();
         Scroll.cancel();
-        startCoord = getCoord( e );
-      } else {
-        prevent( e );
+        save( e );
       }
     }
   }
@@ -125,20 +141,38 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
    * @param e - A TouchEvent or MouseEvent object
    */
   function onPointerMove( e: TouchEvent | MouseEvent ): void {
-    if ( e.cancelable ) {
-      const min = options.dragMinThreshold || 15;
+    if ( ! lastEvent ) {
+      clickPrevented = true;
+      emit( EVENT_DRAG );
+    }
+
+    lastEvent = e;
 
-      if ( isMouse || abs( getCoord( e ) - startCoord ) > min ) {
-        moving = true;
-        onDrag();
+    if ( ! e.cancelable ) {
+      return;
+    }
+
+    if ( isDragging ) {
+      const expired  = timeOf( e ) - timeOf( baseEvent ) > LOG_INTERVAL;
+      const exceeded = hasExceeded !== ( hasExceeded = isExceeded() );
+
+      if ( expired || exceeded ) {
+        save( e );
       }
 
-      if ( moving ) {
-        onDragging( e );
-        prevent( e, true );
+      if ( ! isFade ) {
+        Move.translate( basePosition + constrain( coordOf( e ) - coordOf( baseEvent ) ) );
       }
+
+      emit( EVENT_DRAGGING );
+      prevent( e );
     } else {
-      onPointerUp( e );
+      const threshold = options.dragMinThreshold || 15;
+      isDragging = isMouse || abs( coordOf( e ) - coordOf( baseEvent ) ) > threshold;
+
+      if ( isSliderDirection() ) {
+        prevent( e );
+      }
     }
   }
 
@@ -151,74 +185,61 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
    */
   function onPointerUp( e: TouchEvent | MouseEvent ): void {
     unbind( target, `${ POINTER_MOVE_EVENTS } ${ POINTER_UP_EVENTS }` );
-    moving = false;
 
     if ( lastEvent ) {
-      onDragged( e );
-      lastEvent = null;
+      if ( isDragging || ( e.cancelable && isSliderDirection() ) ) {
+        const velocity    = computeVelocity( e );
+        const destination = computeDestination( velocity );
+
+        if ( isFree ) {
+          Scroll.scroll( destination );
+        } else if ( isFade ) {
+          Controller.go( Splide.index + orient( sign( velocity ) ) );
+        } else {
+          Controller.go( computeIndex( destination ), true );
+        }
+
+        prevent( e );
+      }
+
+      emit( EVENT_DRAGGED );
     }
+
+    isDragging = false;
   }
 
   /**
-   * Called when the user starts dragging the slider.
+   * Saves data at the specific moment.
+   *
+   * @param e  A TouchEvent or MouseEvent object
    */
-  function onDrag(): void {
-    bind( track, 'click', e => {
-      unbind( track, 'click' );
-      prevent( e, true );
-    }, { capture: true } );
-
-    emit( EVENT_DRAG );
+  function save( e: TouchEvent | MouseEvent ): void {
+    prevBaseEvent = baseEvent;
+    baseEvent     = e;
+    basePosition  = getPosition();
   }
 
   /**
-   * Called while the user is dragging the slider.
+   * Called when the track element is clicked.
+   * Disables click any elements inside it while dragging.
    *
-   * @param e - A TouchEvent or MouseEvent object
+   * @param e - A MouseEvent object.
    */
-  function onDragging( e: TouchEvent | MouseEvent ): void {
-    const { timeStamp } = e;
-    const expired = ! lastTime || ( timeStamp - lastTime > SAMPLING_INTERVAL );
-
-    if ( expired || isExceeded() !== exceeded ) {
-      basePosition = getPosition();
-      baseCoord    = getCoord( e );
-      baseTime     = timeStamp;
-    }
-
-    exceeded  = isExceeded();
-    lastTime  = timeStamp;
-    lastEvent = e;
-
-    if ( ! isFade ) {
-      translate( basePosition + constrain( getCoord( e ) - baseCoord ) );
+  function onClick( e: MouseEvent ): void {
+    if ( ! disabled && clickPrevented ) {
+      prevent( e, true );
     }
-
-    emit( EVENT_DRAGGING );
   }
 
   /**
-   * Called when the user finishes dragging.
+   * Checks whether dragging towards the slider or scroll direction.
    *
-   * @param e - A TouchEvent or MouseEvent object
+   * @return `true` if going towards the slider direction, or otherwise `false`.
    */
-  function onDragged( e: TouchEvent | MouseEvent ): void {
-    const velocity = computeVelocity( e );
-
-    if ( isFade ) {
-      go( Splide.index + orient( sign( velocity ) ) );
-    } else {
-      const destination = computeDestination( velocity );
-
-      if ( isFree ) {
-        Scroll.scroll( destination );
-      } else {
-        go( computeIndex( destination ), true );
-      }
-    }
-
-    lastTime = 0;
-    emit( EVENT_DRAGGED );
+  function isSliderDirection(): boolean {
+    const diffX = abs( coordOf( lastEvent ) - coordOf( baseEvent ) );
+    const diffY = abs( coordOf( lastEvent, true ) - coordOf( baseEvent, true ) );
+    return diffX > diffY;
   }
 
   /**
@@ -229,10 +250,11 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
    * @return The drag velocity.
    */
   function computeVelocity( e: TouchEvent | MouseEvent ): number {
-    if ( Splide.is( LOOP ) || ! isExceeded() ) {
-      const diffCoord = getCoord( lastEvent ) - baseCoord;
-      const diffTime  = lastEvent.timeStamp - baseTime;
-      const isFlick   = e.timeStamp - lastTime < SAMPLING_INTERVAL;
+    if ( Splide.is( LOOP ) || ! hasExceeded ) {
+      const base      = baseEvent === lastEvent && prevBaseEvent || baseEvent;
+      const diffCoord = coordOf( lastEvent ) - coordOf( base );
+      const diffTime  = timeOf( e ) - timeOf( base );
+      const isFlick   = timeOf( e ) - timeOf( lastEvent ) < LOG_INTERVAL;
 
       if ( diffTime && isFlick ) {
         return diffCoord / diffTime;
@@ -250,11 +272,9 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
    * @return The destination.
    */
   function computeDestination( velocity: number ): number {
-    const flickPower = options.flickPower || 600;
-
     return getPosition() + sign( velocity ) * min(
-      abs( velocity ) * flickPower,
-      isFree ? Infinity : listSize() * ( options.flickMaxPages || 1 )
+      abs( velocity ) * ( options.flickPower || 600 ),
+      isFree ? Infinity : Components.Layout.listSize() * ( options.flickMaxPages || 1 )
     );
   }
 
@@ -266,20 +286,33 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
    * @return The destination index.
    */
   function computeIndex( destination: number ): number {
-    const dest = toIndex( destination );
-    return isSlide ? clamp( dest, 0, getEnd() ) : dest;
+    const dest = Move.toIndex( destination );
+    return isSlide ? clamp( dest, 0, Controller.getEnd() ) : dest;
   }
 
   /**
    * Returns the `pageX` and `pageY` coordinates provided by the event.
    * Be aware that IE does not support both TouchEvent and MouseEvent constructors.
    *
-   * @param e - A TouchEvent or MouseEvent object.
+   * @param e          - A TouchEvent or MouseEvent object.
+   * @param orthogonal - Optional. If `true`, returns the coord of the orthogonal axis against the drag one.
    *
    * @return A pageX or pageY coordinate.
    */
-  function getCoord( e: TouchEvent | MouseEvent ): number {
-    return ( isMouse ? e : ( e as TouchEvent ).touches[ 0 ] )[ resolve( 'pageX' ) ];
+  function coordOf( e: TouchEvent | MouseEvent, orthogonal?: boolean ): number {
+    const prop = `page${ resolve( orthogonal ? 'Y' : 'X' ) }`;
+    return ( isMouse ? e : ( e as TouchEvent ).touches[ 0 ] )[ prop ];
+  }
+
+  /**
+   * Returns the time stamp in the provided event object.
+   *
+   * @param e - A TouchEvent or MouseEvent object.
+   *
+   * @return A time stamp.
+   */
+  function timeOf( e: TouchEvent | MouseEvent ): number {
+    return e.timeStamp;
   }
 
   /**
@@ -291,10 +324,20 @@ export function Drag( Splide: Splide, Components: Components, options: Options )
    * @return The constrained diff.
    */
   function constrain( diff: number ): number {
-    return diff / ( exceeded && isSlide ? FRICTION : 1 );
+    return diff / ( hasExceeded && isSlide ? FRICTION : 1 );
+  }
+
+  /**
+   * Disables the component.
+   *
+   * @param value - Set `true` to disable the component.
+   */
+  function disable( value: boolean ): void {
+    disabled = value;
   }
 
   return {
     mount,
+    disable,
   };
 }

+ 1 - 1
src/js/components/Drag/constants.ts

@@ -10,7 +10,7 @@ export const FRICTION = 5;
  *
  * @since 3.0.0
  */
-export const SAMPLING_INTERVAL = 50;
+export const LOG_INTERVAL = 50;
 
 /**
  * Start events for dragging.

+ 16 - 9
src/js/components/Keyboard/Keyboard.ts

@@ -68,15 +68,7 @@ export function Keyboard( Splide: Splide, Components: Components, options: Optio
         target = window;
       }
 
-      bind( target, 'keydown', e => {
-        const key = normalize( e.key );
-
-        if ( key === resolve( 'ArrowLeft' ) ) {
-          Splide.go( '<' );
-        } else if ( key === resolve( 'ArrowRight' ) ) {
-          Splide.go( '>' );
-        }
-      } );
+      bind( target, 'keydown', onKeydown );
     }
   }
 
@@ -93,6 +85,21 @@ export function Keyboard( Splide: Splide, Components: Components, options: Optio
     }
   }
 
+  /**
+   * Called when any key is pressed on the target.
+   *
+   * @param e - A KeyboardEvent object.
+   */
+  function onKeydown( e: KeyboardEvent ): void {
+    const key = normalize( e.key );
+
+    if ( key === resolve( 'ArrowLeft' ) ) {
+      Splide.go( '<' );
+    } else if ( key === resolve( 'ArrowRight' ) ) {
+      Splide.go( '>' );
+    }
+  }
+
   /**
    * Absorbs the difference of key names among browsers.
    *

+ 8 - 2
src/js/components/Options/Options.ts

@@ -1,5 +1,6 @@
 import { DATA_ATTRIBUTE } from '../../constants/project';
 import { DESTROYED } from '../../constants/states';
+import { Throttle } from '../../constructors';
 import { Splide } from '../../core/Splide/Splide';
 import { BaseComponent, Components, Options } from '../../types';
 import { assert, find, getAttribute, merge } from '../../utils';
@@ -25,6 +26,11 @@ export interface OptionsComponent extends BaseComponent {
  * @return An Options component object.
  */
 export function Options( Splide: Splide, Components: Components, options: Options ): OptionsComponent {
+  /**
+   * The throttled `observe` function.
+   */
+  const throttledObserve = Throttle( observe );
+
   /**
    * Keeps the initial options to apply when no matched query exists.
    */
@@ -67,7 +73,7 @@ export function Options( Splide: Splide, Components: Components, options: Option
           matchMedia( `(${ options.mediaQuery || 'max' }-width:${ point }px)` ),
         ] );
 
-      addEventListener( 'resize', observe );
+      addEventListener( 'resize', throttledObserve );
       observe();
     }
   }
@@ -79,7 +85,7 @@ export function Options( Splide: Splide, Components: Components, options: Option
    */
   function destroy( completely: boolean ): void {
     if ( completely ) {
-      removeEventListener( 'resize', observe );
+      removeEventListener( 'resize', throttledObserve );
     }
   }
 

+ 25 - 3
src/js/test/php/examples/default.php

@@ -9,7 +9,7 @@ $settings = get_settings();
 <html lang="en">
 <head>
   <meta charset="UTF-8">
-  <meta name="viewport" content="width=device-width,initial-scale=1">
+  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
   <title>Default</title>
 
   <link rel="stylesheet" href="../../../../../dist/css/themes/splide-<?php echo $settings['theme'] ?>.min.css">
@@ -22,20 +22,42 @@ $settings = get_settings();
         perPage: 1,
         gap    : '1rem',
         drag   : 'free',
-        // speed  : 0,
+        height : 200,
+        pagination: false,
+        arrows: false,
+        slideFocus: false,
       } );
 
       splide.on( 'moved', () => {
         console.log( 'moved' );
       } );
 
+      splide.on( 'click', () => {
+        console.log( 'click' );
+      } );
+
       splide.mount();
+
+
+      const pre = document.getElementById( 'message' );
+
+      console.log = ( string ) => {
+        pre.textContent = string + '\n' + pre.textContent;
+      }
     } );
   </script>
+
+  <style>
+    body {
+      margin: 50em 0;
+    }
+  </style>
 </head>
 <body>
+45
+<?php render( 'splide01', 10, true ); ?>
 
-<?php render(); ?>
+<pre id="message"></pre>
 
 </body>
 </html>

+ 9 - 3
src/js/test/php/parts.php

@@ -1,11 +1,17 @@
 <?php
-function render( $id = 'splide01', $number = 10 ) {
+function render( $id = 'splide01', $number = 10, $text = false ) {
   printf( '<div id="%s" class="splide">', $id );
   echo '<div class="splide__track">';
   echo '<ul class="splide__list">';
-  for ( $i = 0; $i < $number; $i ++ ) {
+  for ( $i = 0; $i < $number; $i++ ) {
     echo '<li class="splide__slide">';
-    printf( '<img src="../../assets/images/pics/slide%02d.jpg">', $i + 1 );
+
+    if ( $text ) {
+      printf( '<span>%s</span>', $i + 1 );
+    } else {
+      printf( '<img src="../../assets/images/pics/slide%02d.jpg">', $i + 1 );
+    }
+
     echo '</li>' . PHP_EOL;
   }
   echo '</ul>';

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است