|
13 | 13 | } from '../../utils/event' |
14 | 14 | import { getAdjacentIndexes } from '../../utils/page' |
15 | 15 | import { get } from '../../utils/object' |
16 | | - import { ProgressManager } from '../../utils/ProgressManager.js' |
| 16 | + import { ProgressManager } from '../../utils/ProgressManager' |
| 17 | + import { wait } from '../../utils/interval' |
17 | 18 |
|
18 | 19 | const dispatch = createEventDispatcher() |
19 | 20 |
|
20 | 21 | const autoplayDirectionFnDescription = { |
21 | | - [NEXT]: () => { |
22 | | - progressManager.start(() => { |
23 | | - showNextPage() |
24 | | - }) |
25 | | - }, |
26 | | - [PREV]: () => { |
27 | | - progressManager.start(() => { |
28 | | - showPrevPage() |
29 | | - }) |
30 | | - } |
| 22 | + [NEXT]: async () => await progressManager.start(showNextPage), |
| 23 | + [PREV]: async () => await progressManager.start(showPrevPage) |
31 | 24 | } |
32 | 25 |
|
33 | 26 | const directionFnDescription = { |
34 | | - [NEXT]: () => { |
35 | | - showNextPage() |
36 | | - }, |
37 | | - [PREV]: () => { |
38 | | - showPrevPage() |
39 | | - } |
| 27 | + [NEXT]: showNextPage, |
| 28 | + [PREV]: showPrevPage |
40 | 29 | } |
41 | 30 |
|
42 | 31 | /** |
|
70 | 59 | * Enables autoplay of pages |
71 | 60 | */ |
72 | 61 | export let autoplay = false |
| 62 | + $: { |
| 63 | + applyAutoplayIfNeeded(autoplay) |
| 64 | + } |
73 | 65 |
|
74 | 66 | /** |
75 | 67 | * Autoplay change interval (ms) |
|
96 | 88 | */ |
97 | 89 | export let dots = true |
98 | 90 |
|
99 | | - export function goTo(pageIndex, options) { |
| 91 | + export async function goTo(pageIndex, options) { |
100 | 92 | const animated = get(options, 'animated', true) |
101 | 93 | if (typeof pageIndex !== 'number') { |
102 | 94 | throw new Error('pageIndex should be a number') |
103 | 95 | } |
104 | | - showPage(pageIndex + Number(infinite), { animated }) |
| 96 | + await showPage(pageIndex + Number(infinite), { animated }) |
105 | 97 | } |
106 | 98 |
|
107 | | - export function goToPrev(options) { |
| 99 | + export async function goToPrev(options) { |
108 | 100 | const animated = get(options, 'animated', true) |
109 | | - showPrevPage({ animated }) |
| 101 | + await showPrevPage({ animated }) |
110 | 102 | } |
111 | 103 |
|
112 | | - export function goToNext(options) { |
| 104 | + export async function goToNext(options) { |
113 | 105 | const animated = get(options, 'animated', true) |
114 | | - showNextPage({ animated }) |
| 106 | + await showNextPage({ animated }) |
115 | 107 | } |
116 | 108 |
|
117 | 109 | let store = createStore() |
118 | 110 | let currentPageIndex = 0 |
119 | | - $: originalCurrentPageIndex = currentPageIndex - Number(infinite); |
| 111 | + $: originalCurrentPageIndex = getOriginalCurrentPageIndex(currentPageIndex, pagesCount, infinite) // index without cloenes |
120 | 112 | $: dispatch('pageChange', originalCurrentPageIndex) |
121 | 113 |
|
122 | 114 | let pagesCount = 0 |
123 | 115 | $: originalPagesCount = Math.max(pagesCount - (infinite ? 2 : 0), 1) // without clones |
| 116 | +
|
| 117 | + function getOriginalCurrentPageIndex(currentPageIndex, pagesCount, infinite) { |
| 118 | + if (infinite) { |
| 119 | + const CLONES_COUNT = 2 |
| 120 | + if (currentPageIndex === pagesCount - 1) return 0 |
| 121 | + if (currentPageIndex === 0) return (pagesCount - CLONES_COUNT) - 1 |
| 122 | + return currentPageIndex - 1 |
| 123 | + } |
| 124 | + return currentPageIndex |
| 125 | + } |
| 126 | +
|
124 | 127 | let pageWidth = 0 |
125 | 128 | let offset = 0 |
126 | 129 | let pageWindowElement |
|
169 | 172 | pagesElement.append(first.cloneNode(true)) |
170 | 173 | } |
171 | 174 |
|
172 | | - function applyAutoplayIfNeeded(options) { |
| 175 | + async function applyAutoplayIfNeeded(autoplay) { |
173 | 176 | // prevent progress change if not infinite for first and last page |
174 | 177 | if ( |
175 | 178 | !infinite && ( |
|
180 | 183 | progressManager.reset() |
181 | 184 | return |
182 | 185 | } |
183 | | - if (autoplay) { |
184 | | - const delayMs = get(options, 'delayMs', 0) |
185 | | - if (delayMs) { |
186 | | - setTimeout(() => { |
187 | | - autoplayDirectionFnDescription[autoplayDirection]() |
188 | | - }, delayMs) |
189 | | - } else { |
190 | | - autoplayDirectionFnDescription[autoplayDirection]() |
191 | | - } |
192 | | - } |
| 186 | +
|
| 187 | + autoplay && await autoplayDirectionFnDescription[autoplayDirection]() |
193 | 188 | } |
194 | 189 |
|
195 | 190 | let cleanupFns = [] |
|
211 | 206 | applyPageSizes() |
212 | 207 | } |
213 | 208 |
|
214 | | - applyAutoplayIfNeeded() |
215 | | -
|
216 | 209 | addResizeEventListener(applyPageSizes) |
217 | 210 | })() |
218 | 211 | }) |
|
222 | 215 | cleanupFns.filter(fn => fn && typeof fn === 'function').forEach(fn => fn()) |
223 | 216 | }) |
224 | 217 |
|
225 | | - function handlePageChange(pageIndex) { |
226 | | - showPage(pageIndex + Number(infinite)) |
| 218 | + async function handlePageChange(pageIndex) { |
| 219 | + await showPage(pageIndex + Number(infinite)) |
227 | 220 | } |
228 | 221 |
|
229 | 222 | function offsetPage(animated) { |
230 | | - // _duration is an offset animation time |
231 | | - _duration = animated ? duration : 0 |
232 | | - offset = -currentPageIndex * pageWidth |
| 223 | + return new Promise((resolve) => { |
| 224 | + // _duration is an offset animation time |
| 225 | + _duration = animated ? duration : 0 |
| 226 | + offset = -currentPageIndex * pageWidth |
| 227 | + setTimeout(() => { |
| 228 | + resolve() |
| 229 | + }, _duration) |
| 230 | + }) |
233 | 231 | } |
234 | 232 |
|
235 | 233 | // makes delayed jump to 1st or last element |
236 | | - function jumpIfNeeded() { |
| 234 | + async function jumpIfNeeded() { |
237 | 235 | let jumped = false |
238 | 236 | if (infinite) { |
239 | 237 | if (currentPageIndex === 0) { |
240 | | - // offsetDelayMs should depend on _duration, as it wait when offset finishes |
241 | | - showPage(pagesCount - 2, { offsetDelayMs: _duration, animated: false }) |
| 238 | + await showPage(pagesCount - 2, { animated: false }) |
242 | 239 | jumped = true |
243 | 240 | } else if (currentPageIndex === pagesCount - 1) { |
244 | | - showPage(1, { offsetDelayMs: _duration, animated: false }) |
| 241 | + await showPage(1, { animated: false }) |
245 | 242 | jumped = true |
246 | 243 | } |
247 | 244 | } |
|
250 | 247 |
|
251 | 248 | // Disable page change while animation is in progress |
252 | 249 | let disabled = false |
253 | | - function safeChangePage(cb, options) { |
254 | | - const animated = get(options, 'animated', true) |
| 250 | + async function changePage(updateStoreFn, options) { |
255 | 251 | if (disabled) return |
256 | | - cb() |
257 | 252 | disabled = true |
258 | | - setTimeout(() => { |
259 | | - disabled = false |
260 | | - }, animated ? duration : 0) |
| 253 | +
|
| 254 | + updateStoreFn() |
| 255 | + await offsetPage(get(options, 'animated', true)) |
| 256 | + disabled = false |
| 257 | +
|
| 258 | + const jumped = await jumpIfNeeded() |
| 259 | + !jumped && applyAutoplayIfNeeded(autoplay) // no need to wait it finishes |
261 | 260 | } |
262 | 261 |
|
263 | | - function showPage(pageIndex, options) { |
264 | | - const animated = get(options, 'animated', true) |
265 | | - const offsetDelayMs = get(options, 'offsetDelayMs', 0) |
266 | | - safeChangePage(() => { |
267 | | - store.moveToPage({ pageIndex, pagesCount }) |
268 | | - // delayed page transition, used for infinite autoplay to jump to real page |
269 | | - setTimeout(() => { |
270 | | - offsetPage(animated) |
271 | | - const jumped = jumpIfNeeded() |
272 | | - !jumped && applyAutoplayIfNeeded({ delayMs: _duration }) // while offset animation is in progress (delayMs = _duration ms) wait for it |
273 | | - }, offsetDelayMs) |
274 | | - }, { animated }) |
| 262 | + async function showPage(pageIndex, options) { |
| 263 | + await changePage( |
| 264 | + () => store.moveToPage({ pageIndex, pagesCount }), |
| 265 | + options |
| 266 | + ) |
275 | 267 | } |
276 | | - function showPrevPage(options) { |
277 | | - const animated = get(options, 'animated', true) |
278 | | - safeChangePage(() => { |
279 | | - store.prev({ infinite, pagesCount }) |
280 | | - offsetPage(animated) |
281 | | - const jumped = jumpIfNeeded() |
282 | | - !jumped && applyAutoplayIfNeeded({ delayMs: _duration }) |
283 | | - }, { animated }) |
| 268 | + async function showPrevPage(options) { |
| 269 | + await changePage( |
| 270 | + () => store.prev({ infinite, pagesCount }), |
| 271 | + options |
| 272 | + ) |
284 | 273 | } |
285 | | - function showNextPage(options) { |
286 | | - const animated = get(options, 'animated', true) |
287 | | - safeChangePage(() => { |
288 | | - store.next({ infinite, pagesCount }) |
289 | | - offsetPage(animated) |
290 | | - const jumped = jumpIfNeeded() |
291 | | - !jumped && applyAutoplayIfNeeded({ delayMs: _duration }) |
292 | | - }, { animated }) |
| 274 | + async function showNextPage(options) { |
| 275 | + await changePage( |
| 276 | + () => store.next({ infinite, pagesCount }), |
| 277 | + options |
| 278 | + ) |
293 | 279 | } |
294 | 280 |
|
295 | 281 | // gestures |
296 | 282 | function handleSwipeStart() { |
297 | 283 | _duration = 0 |
298 | 284 | } |
299 | | - function handleThreshold(event) { |
300 | | - directionFnDescription[event.detail.direction]() |
| 285 | + async function handleThreshold(event) { |
| 286 | + await directionFnDescription[event.detail.direction]() |
301 | 287 | } |
302 | 288 | function handleSwipeMove(event) { |
303 | 289 | offset += event.detail.dx |
|
0 commit comments