mirror of https://github.com/docusealco/docuseal
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
5.6 KiB
154 lines
5.6 KiB
export default (() => {
|
|
const storageSupport = "sessionStorage" in window && "BroadcastChannel" in window;
|
|
let pagy = "pagy", storage, sync, tabId;
|
|
if (storageSupport) {
|
|
storage = sessionStorage;
|
|
sync = new BroadcastChannel(pagy);
|
|
tabId = Date.now();
|
|
sync.addEventListener("message", (e) => {
|
|
if (e.data.from) {
|
|
const cutoffs = storage.getItem(e.data.key);
|
|
if (cutoffs) {
|
|
sync.postMessage({ to: e.data.from, key: e.data.key, str: cutoffs });
|
|
}
|
|
} else if (e.data.to) {
|
|
if (e.data.to == tabId) {
|
|
storage.setItem(e.data.key, e.data.str);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
const rjsObserver = new ResizeObserver((entries) => entries.forEach((e) => {
|
|
e.target.querySelectorAll(".pagy-rjs").forEach((el) => el.render());
|
|
}));
|
|
const B64SafeEncode = (unicode) => btoa(String.fromCharCode(...new TextEncoder().encode(unicode))).replace(/[+/=]/g, (m) => m == "+" ? "-" : m == "/" ? "_" : ""), B64Decode = (base64) => new TextDecoder().decode(Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)));
|
|
const randKey = () => Math.floor(Math.random() * 36 ** 3).toString(36);
|
|
const augmentKeynav = async (nav, [storageKey, rootKey, pageKey, last, spliceArgs]) => {
|
|
let augmentPage;
|
|
const browserKey = document.cookie.split(/;\s+/).find((row) => row.startsWith(pagy + "="))?.split("=")[1] ?? randKey();
|
|
document.cookie = pagy + "=" + browserKey;
|
|
if (storageKey && !(storageKey in storage)) {
|
|
sync.postMessage({ from: tabId, key: storageKey });
|
|
await new Promise((resolve) => setTimeout(() => resolve(""), 100));
|
|
if (!(storageKey in storage)) {
|
|
augmentPage = (page) => page + "+" + last;
|
|
}
|
|
}
|
|
if (!augmentPage) {
|
|
if (!storageKey) {
|
|
do {
|
|
storageKey = randKey();
|
|
} while (storageKey in storage);
|
|
}
|
|
const data = storage.getItem(storageKey), cutoffs = data ? JSON.parse(data) : [undefined];
|
|
if (spliceArgs) {
|
|
cutoffs.splice(...spliceArgs);
|
|
storage.setItem(storageKey, JSON.stringify(cutoffs));
|
|
}
|
|
augmentPage = (page) => {
|
|
const pageNum = parseInt(page);
|
|
return B64SafeEncode(JSON.stringify([
|
|
browserKey,
|
|
storageKey,
|
|
pageNum,
|
|
cutoffs.length,
|
|
cutoffs[pageNum - 1],
|
|
cutoffs[pageNum]
|
|
]));
|
|
};
|
|
}
|
|
const search = rootKey ? `${rootKey}%5B${pageKey}%5D` : pageKey;
|
|
const re = new RegExp(`(?<=\\?.*)(\\b${search}=)(\\d+)`);
|
|
for (const a of nav.querySelectorAll("a[href]")) {
|
|
a.href = a.href.replace(re, (_match, prefix, digit) => `${prefix}${augmentPage(digit)}`);
|
|
}
|
|
return augmentPage;
|
|
};
|
|
const buildNavJs = (nav, [
|
|
[before, anchor, current, gap, after],
|
|
pageToken,
|
|
[widths, series, labels],
|
|
keynavArgs
|
|
]) => {
|
|
const parent = nav.parentElement;
|
|
let lastWidth = -1;
|
|
(nav.render = () => {
|
|
const index = widths.findIndex((w) => w < parent.clientWidth);
|
|
if (widths[index] === lastWidth) {
|
|
return;
|
|
}
|
|
let html = before;
|
|
series[index].forEach((item, i) => {
|
|
html += item == "gap" ? gap : (typeof item == "number" ? anchor.replace(pageToken, item) : current).replace("L<", labels?.[index][i] ?? item + "<");
|
|
});
|
|
html += after;
|
|
nav.innerHTML = "";
|
|
nav.insertAdjacentHTML("afterbegin", html);
|
|
lastWidth = widths[index];
|
|
if (keynavArgs && storageSupport) {
|
|
augmentKeynav(nav, keynavArgs);
|
|
}
|
|
})();
|
|
if (nav.classList.contains(pagy + "-rjs")) {
|
|
rjsObserver.observe(parent);
|
|
}
|
|
};
|
|
const initInputNavJs = async (nav, [url_token, pageToken, keynavArgs]) => {
|
|
const augment = keynavArgs && storageSupport ? await augmentKeynav(nav, keynavArgs) : (page) => page;
|
|
initInput(nav, (inputValue) => url_token.replace(pageToken, augment(inputValue)));
|
|
};
|
|
const initLimitTagJs = (span, [from, url_token, page_token, limitToken]) => {
|
|
initInput(span, (inputValue) => {
|
|
return url_token.replace(page_token, Math.max(Math.ceil(from / parseInt(inputValue)), 1)).replace(limitToken, inputValue);
|
|
});
|
|
};
|
|
const initInput = (element, getUrl) => {
|
|
const input = element.querySelector("input"), link = element.querySelector("a");
|
|
let initial = input.value;
|
|
const action = () => {
|
|
if (input.value === initial) {
|
|
return;
|
|
}
|
|
const [min, val, max] = [input.min, input.value, input.max].map((n) => parseInt(n) || 0);
|
|
if (val < min || val > max) {
|
|
input.value = initial;
|
|
input.select();
|
|
return;
|
|
}
|
|
initial = input.value;
|
|
link.href = getUrl(input.value);
|
|
link.click();
|
|
};
|
|
input.addEventListener("focus", () => input.select());
|
|
input.addEventListener("focusout", action);
|
|
input.addEventListener("keypress", (e) => {
|
|
if (e.key == "Enter") {
|
|
action();
|
|
}
|
|
});
|
|
};
|
|
return {
|
|
version: "43.4.4",
|
|
init(arg) {
|
|
const target = arg instanceof HTMLElement ? arg : document, elements = target.querySelectorAll("[data-pagy]");
|
|
for (const element of elements) {
|
|
try {
|
|
const [helperId, ...args] = JSON.parse(B64Decode(element.getAttribute("data-pagy")));
|
|
if (helperId == "k") {
|
|
augmentKeynav(element, ...args);
|
|
} else if (helperId == "snj") {
|
|
buildNavJs(element, args);
|
|
} else if (helperId == "inj") {
|
|
initInputNavJs(element, args);
|
|
} else if (helperId == "ltj") {
|
|
initLimitTagJs(element, args);
|
|
}
|
|
} catch (err) {
|
|
console.warn(`Pagy.init: %o
|
|
%s`, element, err);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
})();
|