Advertisement
Guest User

Untitled

a guest
Apr 21st, 2024
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { goto, pushState as push, replaceState as replace } from '$app/navigation';
  2. import type { StorageAdapter } from 'effector-storage';
  3.  
  4. export type ChangeMethod = (params: URLSearchParams | string, erase?: boolean) => void;
  5.  
  6. export type StateBehavior = 'keep' | 'erase';
  7.  
  8. export interface QueryConfig {
  9.   method?: ChangeMethod;
  10.   state?: StateBehavior;
  11.   serialize?: (value: any) => string;
  12.   deserialize?: (value: string) => any;
  13.   timeout?: number;
  14.   def?: any;
  15. }
  16.  
  17. const keyArea = Symbol(); // eslint-disable-line symbol-description
  18.  
  19. const buffer = new Map<string, any>();
  20. let timeoutId: ReturnType<typeof setTimeout> | undefined;
  21. let scheduled: number | undefined;
  22.  
  23. /*
  24.  * Location change methods list
  25.  */
  26.  
  27. const url = (params: URLSearchParams | string) =>
  28.   location.pathname +
  29.   (params + '' ? '?' + params : '') +
  30.   (location.hash && location.hash !== '#' ? location.hash : '');
  31.  
  32. export const pushState: ChangeMethod = (params, erase): void =>
  33.   push(url(params), erase ? null : history.state);
  34.  
  35. export const replaceState: ChangeMethod = (params, erase): void =>
  36.   replace(url(params), erase ? null : history.state);
  37.  
  38. export const locationAssign: ChangeMethod = (params): Promise<void> => goto(url(params));
  39.  
  40. export const locationReplace: ChangeMethod = (params): Promise<void> =>
  41.   goto(url(params), { replaceState: true });
  42.  
  43. /**
  44.  * Flush buffer to actual location search params
  45.  */
  46. function flush(method: ChangeMethod, state?: StateBehavior) {
  47.   scheduled = undefined;
  48.   if (buffer.size) {
  49.     const params = new URLSearchParams(location.search);
  50.     for (const [name, value] of buffer.entries()) {
  51.       if (value != null) {
  52.         params.set(name, `${value}`);
  53.       } else {
  54.         params.delete(name);
  55.       }
  56.     }
  57.     buffer.clear();
  58.     method(params, state === 'erase');
  59.   }
  60. }
  61.  
  62. /**
  63.  * Query string adapter factory
  64.  */
  65. export function adapter({
  66.   method = pushState,
  67.   state,
  68.   serialize,
  69.   deserialize,
  70.   def = null,
  71.   timeout
  72. }: QueryConfig): StorageAdapter {
  73.   const adapter: StorageAdapter = <State>(key: string, update: (raw?: any) => void) => {
  74.     const updated = () => setTimeout(update, 0);
  75.  
  76.     if (typeof addEventListener !== 'undefined') {
  77.       addEventListener('popstate', updated);
  78.     }
  79.  
  80.     const dispose = () => {
  81.       if (typeof removeEventListener !== 'undefined') {
  82.         removeEventListener('popstate', updated);
  83.       }
  84.     };
  85.  
  86.     return Object.assign(dispose, {
  87.       get() {
  88.         const params = new URLSearchParams(location.search);
  89.         const value = params.get(key);
  90.         return value ? (deserialize ? deserialize(value) : value) : def;
  91.       },
  92.  
  93.       set(value: State) {
  94.         buffer.set(key, serialize ? serialize(value) : value);
  95.  
  96.         if (timeout === undefined) {
  97.           clearTimeout(timeoutId);
  98.           return flush(method, state);
  99.         }
  100.  
  101.         const deadline = Date.now() + timeout;
  102.         if (scheduled === undefined || scheduled > deadline) {
  103.           clearTimeout(timeoutId);
  104.           scheduled = deadline;
  105.           timeoutId = setTimeout(flush, timeout, method, state);
  106.         }
  107.       }
  108.     });
  109.   };
  110.  
  111.   adapter.keyArea = keyArea;
  112.   return adapter;
  113. }
  114.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement