Skip to content

Commit

Permalink
Refactor Frontend:
Browse files Browse the repository at this point in the history
- Improve reliability of URLs and javascript placeholders
- Remove the *_TOKEN constants
- Reduce the size of 'data-pagy' and compiled javascript files
  • Loading branch information
ddnexus committed Dec 29, 2024
1 parent 9ba74d6 commit 5b0d10f
Show file tree
Hide file tree
Showing 24 changed files with 616 additions and 597 deletions.
2 changes: 1 addition & 1 deletion docs/api/console.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pagy_nav(pagy)

pagy_metadata(pagy)
=>
{ :scaffold_url => "http://www.example.com/subdir?page=__pagy_page__",
{ :scaffold_url => "http://www.example.com/subdir?page=P ",
:first_url => "http://www.example.com/subdir?page=1",
:prev_url => "http://www.example.com/subdir?page=2",
:page_url => "http://www.example.com/subdir?page=3",
Expand Down
6 changes: 3 additions & 3 deletions docs/extras/metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,16 @@ the default.
This is a special url string that you can use as the scaffold to build real page urls in your frontend (instead of producing them
on the backend).

It is a pagination url/path (complete with all the params) containing the `__pagy_page__` placeholder in place of the page
number (e.g. `'/foo?page=__pagy_page__&bar=baz'`)
It is a pagination url/path (complete with all the params) containing the `P ` placeholder in place of the page
number (e.g. `'/foo?page=P &bar=baz'`)

You can generate all the actual links on the frontend by simply replacing the placeholder with the actual page number you want to
link to.

In javascript you can do something like:

```js
page_url = scaffold_url.replace(/__pagy_page__/, page_number)
pageUrl = scaffoldUrl.replace("P ", pageNumber)
```

This is particularly useful when you want to build some dynamic pagination UI (e.g. similar to what the `pagy_*combo_js`
Expand Down
300 changes: 150 additions & 150 deletions e2e/snapshots.js

Large diffs are not rendered by default.

43 changes: 21 additions & 22 deletions gem/javascripts/pagy.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions gem/javascripts/pagy.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion gem/javascripts/pagy.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 20 additions & 21 deletions gem/javascripts/pagy.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const Pagy = (() => {
const storageSupport = "sessionStorage" in window && "BroadcastChannel" in window;
const storageSupport = "sessionStorage" in window && "BroadcastChannel" in window, pageRe = "P ";
let storage, sync, tabId;
if (storageSupport) {
storage = sessionStorage;
Expand All @@ -9,17 +9,17 @@ const Pagy = (() => {
if (e.data.from) {
const cutoffs = storage.getItem(e.data.key);
if (cutoffs) {
sync.postMessage({ to: e.data.from, key: e.data.key, 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.cutoffs);
storage.setItem(e.data.key, e.data.str);
}
}
});
}
const rjsObserver = new ResizeObserver((entries) => entries.forEach((e) => {
e.target.querySelectorAll(".pagy-rjs").forEach((el) => el.pagyRender());
e.target.querySelectorAll(".pagy-rjs").forEach((el) => el.init());
}));
const B64Encode = (unicode) => btoa(String.fromCharCode(...new TextEncoder().encode(unicode))), B64Safe = (unsafe) => unsafe.replace(/=/g, "").replace(/[+/]/g, (match) => match == "+" ? "-" : "_"), B64SafeEncode = (unicode) => B64Safe(B64Encode(unicode)), B64Decode = (base64) => new TextDecoder().decode(Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)));
const initCutoffs = async (el, [pageSym, [storageKey, spliceArgs]]) => {
Expand Down Expand Up @@ -52,30 +52,29 @@ const Pagy = (() => {
a.href = url.replace(re, `${pageSym}=${value}`);
}
};
const initNavJs = (el, [tokens, sequels, labelSequels, cutoffArgs]) => {
const container = el.parentElement ?? el, widths = Object.keys(sequels).map((w) => parseInt(w)).sort((a, b) => b - a);
const initNavJs = (el, [[before, a, current, gap, after], sequels, labelSequels, cutoffArgs]) => {
const container = el.parentElement ?? el, widths = Object.keys(sequels).map((w) => parseInt(w)).sort((a, b) => b - a), fillIn = (a, page, label) => a.replace(pageRe, page).replace("T<", label + "<");
let lastWidth = -1;
const fillIn = (a, page, label) => a.replace(/__pagy_page__/g, page).replace(/__pagy_label__/g, label);
(el.pagyRender = () => {
(el.init = () => {
const width = widths.find((w) => w < container.clientWidth) || 0;
if (width === lastWidth) {
return;
}
let html = tokens.before;
let html = before;
const series = sequels[width.toString()], labels = labelSequels?.[width.toString()] ?? series.map((l) => l.toString());
series.forEach((item, i) => {
const label = labels[i];
let filled;
if (typeof item == "number") {
filled = fillIn(tokens.a, item.toString(), label);
filled = fillIn(a, item.toString(), label);
} else if (item == "gap") {
filled = tokens.gap;
filled = gap;
} else {
filled = fillIn(tokens.current, item, label);
filled = fillIn(current, item, label);
}
html += filled;
});
html += tokens.after;
html += after;
el.innerHTML = "";
el.insertAdjacentHTML("afterbegin", html);
lastWidth = width;
Expand All @@ -87,11 +86,11 @@ const Pagy = (() => {
rjsObserver.observe(container);
}
};
const initComboJs = (el, [url_token]) => initInput(el, (inputValue) => url_token.replace(/__pagy_page__/, inputValue));
const initComboJs = (el, [url_token]) => initInput(el, (inputValue) => url_token.replace(pageRe, inputValue));
const initSelectorJs = (el, [from, url_token]) => {
initInput(el, (inputValue) => {
const page = Math.max(Math.ceil(from / parseInt(inputValue)), 1).toString();
return url_token.replace(/__pagy_page__/, page).replace(/__pagy_limit__/, inputValue);
return url_token.replace(pageRe, page).replace("L ", inputValue);
});
};
const initInput = (el, getUrl) => {
Expand Down Expand Up @@ -122,18 +121,18 @@ const Pagy = (() => {
const target = arg instanceof Element ? arg : document, elements = target.querySelectorAll("[data-pagy]");
for (const el of elements) {
try {
const [keyword, ...args] = JSON.parse(B64Decode(el.getAttribute("data-pagy")));
if (keyword == "nav") {
const [key, ...args] = JSON.parse(B64Decode(el.getAttribute("data-pagy")));
if (key == "n") {
initCutoffs(el, args);
} else if (keyword == "nav_js") {
} else if (key == "nj") {
initNavJs(el, args);
} else if (keyword == "combo_js") {
} else if (key == "cj") {
initComboJs(el, args);
} else if (keyword == "selector_js") {
} else if (key == "sj") {
initSelectorJs(el, args);
}
} catch (err) {
console.warn("Pagy.init() error: %o\n%s", el, err);
console.warn("Pagy.init: %o\n%s", el, err);
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions gem/lib/pagy/extras/bootstrap.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ module BootstrapExtra
def pagy_bootstrap_nav(pagy, id: nil, classes: 'pagination', aria_label: nil, **vars)
id = %( id="#{id}") if id
a = pagy_anchor(pagy, **vars)
data = %( #{pagy_data(pagy, :nav)}) if defined?(::Pagy::KeysetForUI) && pagy.is_a?(KeysetForUI)
data = %( #{pagy_data(pagy, :n)}) if defined?(::Pagy::KeysetForUI) && pagy.is_a?(KeysetForUI)

html = %(<nav#{id} class="pagy-bootstrap nav" #{nav_aria_label(pagy, aria_label:)}#{data
}><ul class="#{classes}">#{bootstrap_prev_html(pagy, a)})
Expand All @@ -37,16 +37,16 @@ def pagy_bootstrap_nav_js(pagy, id: nil, classes: 'pagination', aria_label: nil,
id = %( id="#{id}") if id
a = pagy_anchor(pagy, **vars)
tokens = { before: %(<ul class="#{classes}">#{bootstrap_prev_html(pagy, a)}),
a: %(<li class="page-item">#{a.(PAGE_TOKEN, LABEL_TOKEN, classes: 'page-link')}</li>),
a: %(<li class="page-item">#{JST.token(a.('P', 'T', classes: 'page-link'), pagy.vars[:page_sym])}</li>),
current: %(<li class="page-item active"><a role="link" class="page-link" ) +
%(aria-current="page" aria-disabled="true">#{LABEL_TOKEN}</a></li>),
%(aria-current="page" aria-disabled="true">T</a></li>),
gap: %(<li class="page-item gap disabled"><a role="link" class="page-link" aria-disabled="true">#{
pagy_t('pagy.gap')}</a></li>),
after: %(#{bootstrap_next_html pagy, a}</ul>) }

%(<nav#{id} class="#{'pagy-rjs ' if sequels.size > 1}pagy-bootstrap nav-js" #{
nav_aria_label(pagy, aria_label:)} #{
pagy_data(pagy, :nav_js, tokens, sequels, pagy.label_sequels(sequels))
pagy_data(pagy, :nj, tokens.values, sequels, pagy.label_sequels(sequels))
}></nav>)
end

Expand All @@ -62,7 +62,7 @@ def pagy_bootstrap_combo_nav_js(pagy, id: nil, classes: 'pagination', aria_label

%(<nav#{id} class="pagy-bootstrap combo-nav-js" #{
nav_aria_label(pagy, aria_label:)} #{
pagy_data(pagy, :combo_js, pagy_url_for(pagy, PAGE_TOKEN, **vars))
pagy_data(pagy, :cj, JST.token(pagy_url_for(pagy, 'P', **vars), pagy.vars[:page_sym]))
}><ul class="#{classes}">#{
bootstrap_prev_html(pagy, a)
}<li class="page-item pagy-bootstrap"><label class="page-link">#{
Expand Down
Loading

0 comments on commit 5b0d10f

Please sign in to comment.