pagy 9.4.0 → 43.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. checksums.yaml +4 -4
  2. data/apps/calendar.ru +548 -552
  3. data/apps/demo.ru +224 -181
  4. data/apps/index.rb +3 -1
  5. data/apps/keynav+root_key.ru +321 -0
  6. data/apps/keynav.ru +260 -0
  7. data/apps/{keyset_ar.ru → keyset.ru} +26 -32
  8. data/apps/{keyset_s.ru → keyset_sequel.ru} +23 -29
  9. data/apps/rails.ru +51 -48
  10. data/apps/repro.ru +51 -47
  11. data/bin/pagy +20 -21
  12. data/config/pagy.rb +35 -207
  13. data/javascripts/ai_widget.js +90 -0
  14. data/javascripts/pagy.js +153 -0
  15. data/javascripts/pagy.js.map +10 -0
  16. data/javascripts/pagy.min.js +2 -4
  17. data/javascripts/pagy.mjs +113 -63
  18. data/javascripts/wand.js +1172 -0
  19. data/lib/pagy/classes/calendar/calendar.rb +96 -0
  20. data/lib/pagy/{calendar → classes/calendar}/day.rb +7 -11
  21. data/lib/pagy/{calendar → classes/calendar}/month.rb +5 -10
  22. data/lib/pagy/{calendar → classes/calendar}/quarter.rb +10 -15
  23. data/lib/pagy/classes/calendar/unit.rb +93 -0
  24. data/lib/pagy/{calendar → classes/calendar}/week.rb +5 -9
  25. data/lib/pagy/{calendar → classes/calendar}/year.rb +5 -6
  26. data/lib/pagy/classes/exceptions.rb +25 -0
  27. data/lib/pagy/classes/keyset/active_record.rb +11 -0
  28. data/lib/pagy/classes/keyset/adapters/active_record.rb +50 -0
  29. data/lib/pagy/classes/keyset/adapters/sequel.rb +63 -0
  30. data/lib/pagy/classes/keyset/keynav/active_record.rb +13 -0
  31. data/lib/pagy/classes/keyset/keynav/sequel.rb +13 -0
  32. data/lib/pagy/classes/keyset/keynav.rb +79 -0
  33. data/lib/pagy/classes/keyset/keyset.rb +126 -0
  34. data/lib/pagy/classes/keyset/sequel.rb +11 -0
  35. data/lib/pagy/classes/offset/countish.rb +17 -0
  36. data/lib/pagy/classes/offset/countless.rb +61 -0
  37. data/lib/pagy/classes/offset/offset.rb +56 -0
  38. data/lib/pagy/classes/offset/search.rb +32 -0
  39. data/lib/pagy/classes/request.rb +36 -0
  40. data/lib/pagy/console.rb +3 -20
  41. data/lib/pagy/modules/abilities/configurable.rb +36 -0
  42. data/lib/pagy/modules/abilities/countable.rb +23 -0
  43. data/lib/pagy/modules/abilities/linkable.rb +60 -0
  44. data/lib/pagy/modules/abilities/rangeable.rb +16 -0
  45. data/lib/pagy/modules/abilities/shiftable.rb +12 -0
  46. data/lib/pagy/{b64.rb → modules/b64.rb} +3 -7
  47. data/lib/pagy/modules/console.rb +24 -0
  48. data/lib/pagy/modules/i18n/i18n.rb +48 -0
  49. data/lib/pagy/modules/i18n/p11n/arabic.rb +29 -0
  50. data/lib/pagy/modules/i18n/p11n/east_slavic.rb +26 -0
  51. data/lib/pagy/modules/i18n/p11n/one_other.rb +15 -0
  52. data/lib/pagy/modules/i18n/p11n/one_upto_two_other.rb +15 -0
  53. data/lib/pagy/modules/i18n/p11n/other.rb +13 -0
  54. data/lib/pagy/modules/i18n/p11n/polish.rb +26 -0
  55. data/lib/pagy/modules/i18n/p11n/west_slavic.rb +22 -0
  56. data/lib/pagy/modules/i18n/p11n.rb +16 -0
  57. data/lib/pagy/modules/searcher.rb +17 -0
  58. data/lib/pagy/toolbox/helpers/anchor_tags.rb +25 -0
  59. data/lib/pagy/toolbox/helpers/bootstrap/input_nav_js.rb +24 -0
  60. data/lib/pagy/toolbox/helpers/bootstrap/previous_next_html.rb +18 -0
  61. data/lib/pagy/toolbox/helpers/bootstrap/series_nav.rb +29 -0
  62. data/lib/pagy/toolbox/helpers/bootstrap/series_nav_js.rb +21 -0
  63. data/lib/pagy/toolbox/helpers/bulma/input_nav_js.rb +21 -0
  64. data/lib/pagy/toolbox/helpers/bulma/previous_next_html.rb +19 -0
  65. data/lib/pagy/toolbox/helpers/bulma/series_nav.rb +28 -0
  66. data/lib/pagy/toolbox/helpers/bulma/series_nav_js.rb +20 -0
  67. data/lib/pagy/toolbox/helpers/data_hash.rb +27 -0
  68. data/lib/pagy/toolbox/helpers/headers_hash.rb +29 -0
  69. data/lib/pagy/toolbox/helpers/info_tag.rb +26 -0
  70. data/lib/pagy/toolbox/helpers/input_nav_js.rb +18 -0
  71. data/lib/pagy/toolbox/helpers/limit_tag_js.rb +23 -0
  72. data/lib/pagy/toolbox/helpers/loader.rb +33 -0
  73. data/lib/pagy/toolbox/helpers/page_url.rb +18 -0
  74. data/lib/pagy/toolbox/helpers/series_nav.rb +28 -0
  75. data/lib/pagy/toolbox/helpers/series_nav_js.rb +18 -0
  76. data/lib/pagy/toolbox/helpers/support/a_lambda.rb +35 -0
  77. data/lib/pagy/toolbox/helpers/support/data_pagy_attribute.rb +15 -0
  78. data/lib/pagy/toolbox/helpers/support/nav_aria_label_attribute.rb +12 -0
  79. data/lib/pagy/toolbox/helpers/support/series.rb +38 -0
  80. data/lib/pagy/toolbox/helpers/support/wrap_input_nav_js.rb +20 -0
  81. data/lib/pagy/toolbox/helpers/support/wrap_series_nav.rb +17 -0
  82. data/lib/pagy/toolbox/helpers/support/wrap_series_nav_js.rb +37 -0
  83. data/lib/pagy/toolbox/helpers/urls_hash.rb +13 -0
  84. data/lib/pagy/toolbox/paginators/calendar.rb +29 -0
  85. data/lib/pagy/toolbox/paginators/countish.rb +37 -0
  86. data/lib/pagy/toolbox/paginators/countless.rb +20 -0
  87. data/lib/pagy/toolbox/paginators/elasticsearch_rails.rb +50 -0
  88. data/lib/pagy/toolbox/paginators/keynav_js.rb +26 -0
  89. data/lib/pagy/toolbox/paginators/keyset.rb +15 -0
  90. data/lib/pagy/toolbox/paginators/meilisearch.rb +31 -0
  91. data/lib/pagy/toolbox/paginators/method.rb +35 -0
  92. data/lib/pagy/toolbox/paginators/offset.rb +18 -0
  93. data/lib/pagy/toolbox/paginators/searchkick.rb +31 -0
  94. data/lib/pagy.rb +59 -97
  95. data/locales/ar.yml +9 -6
  96. data/locales/be.yml +9 -6
  97. data/locales/bg.yml +9 -6
  98. data/locales/bs.yml +9 -6
  99. data/locales/ca.yml +9 -6
  100. data/locales/ckb.yml +8 -6
  101. data/locales/cs.yml +9 -6
  102. data/locales/da.yml +9 -6
  103. data/locales/de.yml +9 -6
  104. data/locales/dz.yml +9 -6
  105. data/locales/en.yml +9 -6
  106. data/locales/es.yml +9 -6
  107. data/locales/fr.yml +9 -6
  108. data/locales/hr.yml +9 -6
  109. data/locales/id.yml +10 -9
  110. data/locales/it.yml +9 -6
  111. data/locales/ja.yml +10 -9
  112. data/locales/km.yml +10 -9
  113. data/locales/ko.yml +9 -6
  114. data/locales/nb.yml +9 -6
  115. data/locales/nl.yml +9 -6
  116. data/locales/nn.yml +9 -6
  117. data/locales/pl.yml +9 -6
  118. data/locales/pt-BR.yml +10 -7
  119. data/locales/pt.yml +10 -7
  120. data/locales/ru.yml +9 -6
  121. data/locales/sk.yml +9 -6
  122. data/locales/sr.yml +9 -6
  123. data/locales/sv-SE.yml +9 -6
  124. data/locales/sv.yml +9 -6
  125. data/locales/sw.yml +12 -9
  126. data/locales/ta.yml +9 -6
  127. data/locales/tr.yml +17 -12
  128. data/locales/uk.yml +9 -6
  129. data/locales/vi.yml +9 -6
  130. data/locales/zh-CN.yml +9 -6
  131. data/locales/zh-HK.yml +9 -6
  132. data/locales/zh-TW.yml +9 -6
  133. data/stylesheets/pagy-tailwind.css +64 -0
  134. data/stylesheets/pagy.css +63 -27
  135. metadata +118 -52
  136. data/javascripts/pagy.min.js.map +0 -10
  137. data/lib/pagy/backend.rb +0 -44
  138. data/lib/pagy/calendar/unit.rb +0 -103
  139. data/lib/pagy/calendar.rb +0 -84
  140. data/lib/pagy/countless.rb +0 -38
  141. data/lib/pagy/exceptions.rb +0 -25
  142. data/lib/pagy/extras/arel.rb +0 -28
  143. data/lib/pagy/extras/array.rb +0 -19
  144. data/lib/pagy/extras/bootstrap.rb +0 -97
  145. data/lib/pagy/extras/bulma.rb +0 -93
  146. data/lib/pagy/extras/calendar.rb +0 -79
  147. data/lib/pagy/extras/countless.rb +0 -32
  148. data/lib/pagy/extras/elasticsearch_rails.rb +0 -71
  149. data/lib/pagy/extras/gearbox.rb +0 -55
  150. data/lib/pagy/extras/headers.rb +0 -54
  151. data/lib/pagy/extras/i18n.rb +0 -26
  152. data/lib/pagy/extras/js_tools.rb +0 -70
  153. data/lib/pagy/extras/jsonapi.rb +0 -88
  154. data/lib/pagy/extras/keyset.rb +0 -30
  155. data/lib/pagy/extras/limit.rb +0 -63
  156. data/lib/pagy/extras/meilisearch.rb +0 -57
  157. data/lib/pagy/extras/metadata.rb +0 -42
  158. data/lib/pagy/extras/overflow.rb +0 -81
  159. data/lib/pagy/extras/pagy.rb +0 -82
  160. data/lib/pagy/extras/searchkick.rb +0 -59
  161. data/lib/pagy/extras/size.rb +0 -40
  162. data/lib/pagy/extras/standalone.rb +0 -60
  163. data/lib/pagy/extras/trim.rb +0 -29
  164. data/lib/pagy/frontend.rb +0 -99
  165. data/lib/pagy/i18n.rb +0 -167
  166. data/lib/pagy/keyset/active_record.rb +0 -44
  167. data/lib/pagy/keyset/sequel.rb +0 -57
  168. data/lib/pagy/keyset.rb +0 -118
  169. data/lib/pagy/shared_methods.rb +0 -26
  170. data/lib/pagy/url_helpers.rb +0 -26
  171. data/stylesheets/pagy.scss +0 -48
  172. data/stylesheets/pagy.tailwind.css +0 -21
data/javascripts/pagy.mjs CHANGED
@@ -1,52 +1,108 @@
1
1
  const Pagy = (() => {
2
- const rjsObserver = new ResizeObserver((entries) => entries.forEach((e) => e.target.querySelectorAll(".pagy-rjs").forEach((el) => el.pagyRender())));
3
- const initNav = (el, [tokens, sequels, labelSequels, trimParam]) => {
4
- const container = el.parentElement ?? el;
5
- const widths = Object.keys(sequels).map((w) => parseInt(w)).sort((a, b) => b - a);
2
+ const storageSupport = "sessionStorage" in window && "BroadcastChannel" in window, pageRe = "P ";
3
+ let pagy = "pagy", storage, sync, tabId;
4
+ if (storageSupport) {
5
+ storage = sessionStorage;
6
+ sync = new BroadcastChannel(pagy);
7
+ tabId = Date.now();
8
+ sync.addEventListener("message", (e) => {
9
+ if (e.data.from) {
10
+ const cutoffs = storage.getItem(e.data.key);
11
+ if (cutoffs) {
12
+ sync.postMessage({ to: e.data.from, key: e.data.key, str: cutoffs });
13
+ }
14
+ } else if (e.data.to) {
15
+ if (e.data.to == tabId) {
16
+ storage.setItem(e.data.key, e.data.str);
17
+ }
18
+ }
19
+ });
20
+ }
21
+ const rjsObserver = new ResizeObserver((entries) => entries.forEach((e) => {
22
+ e.target.querySelectorAll(".pagy-rjs").forEach((el) => el.render());
23
+ }));
24
+ 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)));
25
+ const randKey = () => Math.floor(Math.random() * 36 ** 3).toString(36);
26
+ const augmentKeynav = async (nav, [storageKey, rootKey, pageKey, last, spliceArgs]) => {
27
+ let augmentPage;
28
+ const browserKey = document.cookie.split(/;\s+/).find((row) => row.startsWith(pagy + "="))?.split("=")[1] ?? randKey();
29
+ document.cookie = pagy + "=" + browserKey;
30
+ if (storageKey && !(storageKey in storage)) {
31
+ sync.postMessage({ from: tabId, key: storageKey });
32
+ await new Promise((resolve) => setTimeout(() => resolve(""), 100));
33
+ if (!(storageKey in storage)) {
34
+ augmentPage = (page) => page + "+" + last;
35
+ }
36
+ }
37
+ if (!augmentPage) {
38
+ if (!storageKey) {
39
+ do {
40
+ storageKey = randKey();
41
+ } while (storageKey in storage);
42
+ }
43
+ const data = storage.getItem(storageKey), cutoffs = data ? JSON.parse(data) : [undefined];
44
+ if (spliceArgs) {
45
+ cutoffs.splice(...spliceArgs);
46
+ storage.setItem(storageKey, JSON.stringify(cutoffs));
47
+ }
48
+ augmentPage = (page) => {
49
+ const pageNum = parseInt(page);
50
+ return B64SafeEncode(JSON.stringify([
51
+ browserKey,
52
+ storageKey,
53
+ pageNum,
54
+ cutoffs.length,
55
+ cutoffs[pageNum - 1],
56
+ cutoffs[pageNum]
57
+ ]));
58
+ };
59
+ }
60
+ const search = rootKey ? `${rootKey}%5B${pageKey}%5D` : pageKey;
61
+ const re = new RegExp(`(?<=\\?.*)(\\b${search}=)(\\d+)`);
62
+ for (const a of nav.querySelectorAll("a[href]")) {
63
+ a.href = a.href.replace(re, (_match, prefix, digit) => `${prefix}${augmentPage(digit)}`);
64
+ }
65
+ return augmentPage;
66
+ };
67
+ const buildNavJs = (nav, [
68
+ [before, anchor, current, gap, after],
69
+ [widths, series, labels],
70
+ keynavArgs
71
+ ]) => {
72
+ const parent = nav.parentElement;
6
73
  let lastWidth = -1;
7
- const fillIn = (a, page, label) => a.replace(/__pagy_page__/g, page).replace(/__pagy_label__/g, label);
8
- (el.pagyRender = function() {
9
- const width = widths.find((w) => w < container.clientWidth) || 0;
10
- if (width === lastWidth) {
74
+ (nav.render = () => {
75
+ const index = widths.findIndex((w) => w < parent.clientWidth);
76
+ if (widths[index] === lastWidth) {
11
77
  return;
12
78
  }
13
- let html = tokens.before;
14
- const series = sequels[width.toString()];
15
- const labels = labelSequels?.[width.toString()] ?? series.map((l) => l.toString());
16
- series.forEach((item, i) => {
17
- const label = labels[i];
18
- let filled;
19
- if (typeof item === "number") {
20
- filled = fillIn(tokens.a, item.toString(), label);
21
- } else if (item === "gap") {
22
- filled = tokens.gap;
23
- } else {
24
- filled = fillIn(tokens.current, item, label);
25
- }
26
- html += typeof trimParam === "string" && item == 1 ? trim(filled, trimParam) : filled;
79
+ let html = before;
80
+ series[index].forEach((item, i) => {
81
+ html += item == "gap" ? gap : (typeof item == "number" ? anchor.replace(pageRe, item) : current).replace("L<", labels?.[index][i] ?? item + "<");
27
82
  });
28
- html += tokens.after;
29
- el.innerHTML = "";
30
- el.insertAdjacentHTML("afterbegin", html);
31
- lastWidth = width;
83
+ html += after;
84
+ nav.innerHTML = "";
85
+ nav.insertAdjacentHTML("afterbegin", html);
86
+ lastWidth = widths[index];
87
+ if (keynavArgs && storageSupport) {
88
+ augmentKeynav(nav, keynavArgs);
89
+ }
32
90
  })();
33
- if (el.classList.contains("pagy-rjs")) {
34
- rjsObserver.observe(container);
91
+ if (nav.classList.contains(pagy + "-rjs")) {
92
+ rjsObserver.observe(parent);
35
93
  }
36
94
  };
37
- const initCombo = (el, [url_token, trimParam]) => initInput(el, (inputValue) => [inputValue, url_token.replace(/__pagy_page__/, inputValue)], trimParam);
38
- const initSelector = (el, [from, url_token, trimParam]) => {
39
- initInput(el, (inputValue) => {
40
- const page = Math.max(Math.ceil(from / parseInt(inputValue)), 1).toString();
41
- const url = url_token.replace(/__pagy_page__/, page).replace(/__pagy_limit__/, inputValue);
42
- return [page, url];
43
- }, trimParam);
95
+ const initInputNavJs = async (nav, [url_token, keynavArgs]) => {
96
+ const augment = keynavArgs && storageSupport ? await augmentKeynav(nav, keynavArgs) : (page) => page;
97
+ initInput(nav, (inputValue) => url_token.replace(pageRe, augment(inputValue)));
98
+ };
99
+ const initLimitTagJs = (span, [from, url_token]) => {
100
+ initInput(span, (inputValue) => {
101
+ return url_token.replace(pageRe, Math.max(Math.ceil(from / parseInt(inputValue)), 1)).replace("L ", inputValue);
102
+ });
44
103
  };
45
- const initInput = (el, getVars, trimParam) => {
46
- const input = el.querySelector("input");
47
- const link = el.querySelector("a");
48
- const initial = input.value;
49
- const action = function() {
104
+ const initInput = (element, getUrl) => {
105
+ const input = element.querySelector("input"), link = element.querySelector("a"), initial = input.value, action = () => {
50
106
  if (input.value === initial) {
51
107
  return;
52
108
  }
@@ -56,42 +112,36 @@ const Pagy = (() => {
56
112
  input.select();
57
113
  return;
58
114
  }
59
- let [page, url] = getVars(input.value);
60
- if (typeof trimParam === "string" && page === "1") {
61
- url = trim(url, trimParam);
62
- }
63
- link.href = url;
115
+ link.href = getUrl(input.value);
64
116
  link.click();
65
117
  };
66
- ["change", "focus"].forEach((e) => input.addEventListener(e, () => input.select()));
118
+ input.addEventListener("focus", () => input.select());
67
119
  input.addEventListener("focusout", action);
68
120
  input.addEventListener("keypress", (e) => {
69
- if (e.key === "Enter") {
121
+ if (e.key == "Enter") {
70
122
  action();
71
123
  }
72
124
  });
73
125
  };
74
- const trim = (a, param) => a.replace(new RegExp(`[?&]${param}=1\\b(?!&)|\\b${param}=1&`), "");
75
126
  return {
76
- version: "9.4.0",
127
+ version: "43.2.0",
77
128
  init(arg) {
78
- const target = arg instanceof Element ? arg : document;
79
- const elements = target.querySelectorAll("[data-pagy]");
80
- for (const el of elements) {
129
+ const target = arg instanceof HTMLElement ? arg : document, elements = target.querySelectorAll("[data-pagy]");
130
+ for (const element of elements) {
81
131
  try {
82
- const uint8array = Uint8Array.from(atob(el.getAttribute("data-pagy")), (c) => c.charCodeAt(0));
83
- const [keyword, ...args] = JSON.parse(new TextDecoder().decode(uint8array));
84
- if (keyword === "nav") {
85
- initNav(el, args);
86
- } else if (keyword === "combo") {
87
- initCombo(el, args);
88
- } else if (keyword === "selector") {
89
- initSelector(el, args);
90
- } else {
91
- console.warn("Skipped Pagy.init() for: %o\nUnknown keyword '%s'", el, keyword);
132
+ const [helperId, ...args] = JSON.parse(B64Decode(element.getAttribute("data-pagy")));
133
+ if (helperId == "k") {
134
+ augmentKeynav(element, ...args);
135
+ } else if (helperId == "snj") {
136
+ buildNavJs(element, args);
137
+ } else if (helperId == "inj") {
138
+ initInputNavJs(element, args);
139
+ } else if (helperId == "ltj") {
140
+ initLimitTagJs(element, args);
92
141
  }
93
142
  } catch (err) {
94
- console.warn("Skipped Pagy.init() for: %o\n%s", el, err);
143
+ console.warn(`Pagy.init: %o
144
+ %s`, element, err);
95
145
  }
96
146
  }
97
147
  }