Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | 47x 47x 44x 25x 17x 8x 4x 4x 1x 1x 7x 7x 7x 6x 6x 7x 6x 5x 5x 7x 7x | import { computed, inject, ref, warn, type ComputedRef, type InjectionKey } from "vue";
/** The three router methods used, so vue-router is not a dependency. */
export interface RouterLike {
beforeEach(guard: (...args: never[]) => unknown): () => void;
afterEach(hook: (...args: never[]) => unknown): () => void;
onError(handler: (...args: never[]) => unknown): () => void;
}
export interface PageProgress {
/** True while at least one started task has not finished. */
readonly loading: ComputedRef<boolean>;
/** Marks one task as started. Every start() needs a matching done(). */
start(): void;
/** Marks one task as finished. Extra calls are ignored. */
done(): void;
}
/**
* The state behind <PageProgress>: a counter of running tasks, so several
* parallel requests keep the bar up until the last one finishes. It holds
* no timers (the bar's own component does the animation), so it is safe to
* create on the server.
*/
export function createPageProgress(): PageProgress {
const pending = ref(0);
return {
loading: computed(() => pending.value > 0),
start() {
pending.value++;
},
done() {
pending.value = Math.max(0, pending.value - 1);
},
};
}
export const PAGE_PROGRESS: InjectionKey<PageProgress> = Symbol("vue-smart-loading-kit:page-progress");
/**
* The app's page progress (created by the plugin), to wrap any task:
* const progress = usePageProgress()
* progress.start(); await fetchData(); progress.done()
*/
export function usePageProgress(): PageProgress {
const progress = inject(PAGE_PROGRESS, null);
if (progress) return progress;
warn(
"[vue-smart-loading-kit] usePageProgress() needs the plugin: app.use(VueSmartLoadingKit). " +
"Without it, start() and done() do nothing."
);
return createPageProgress();
}
/**
* Starts the bar when a navigation begins and finishes it when it ends or
* fails. A navigation holds exactly one slot however many times it is
* redirected, and only releases its own slot, so it never ends a task that
* was started manually.
*/
export function bindRouter(progress: PageProgress, router: RouterLike): () => void {
let navigating = false;
const begin = () => {
if (navigating) return;
navigating = true;
progress.start();
};
const end = () => {
if (!navigating) return;
navigating = false;
progress.done();
};
const offs = [router.beforeEach(begin), router.afterEach(end), router.onError(end)];
return () => offs.forEach((off) => off());
}
|