pagy 43.3.1 → 43.3.2

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/apps/calendar.ru +1 -1
  3. data/apps/demo.ru +1 -1
  4. data/apps/keynav+root_key.ru +1 -1
  5. data/apps/keynav.ru +1 -1
  6. data/apps/keyset.ru +1 -1
  7. data/apps/keyset_sequel.ru +1 -1
  8. data/apps/rails.ru +1 -1
  9. data/apps/repro.ru +1 -1
  10. data/config/pagy.rb +1 -1
  11. data/javascripts/pagy.js +2 -2
  12. data/javascripts/pagy.js.map +2 -2
  13. data/javascripts/pagy.min.js +1 -1
  14. data/javascripts/pagy.mjs +1 -1
  15. data/lib/pagy/classes/calendar/unit.rb +1 -0
  16. data/lib/pagy/classes/keyset/adapters/active_record.rb +2 -2
  17. data/lib/pagy/classes/keyset/keynav.rb +2 -0
  18. data/lib/pagy/classes/offset/offset.rb +2 -1
  19. data/lib/pagy/modules/i18n/i18n.rb +4 -4
  20. data/lib/pagy/toolbox/helpers/anchor_tags.rb +6 -4
  21. data/lib/pagy/toolbox/helpers/bootstrap/input_nav_js.rb +17 -15
  22. data/lib/pagy/toolbox/helpers/bootstrap/previous_next_html.rb +13 -11
  23. data/lib/pagy/toolbox/helpers/bootstrap/series_nav.rb +22 -20
  24. data/lib/pagy/toolbox/helpers/bootstrap/series_nav_js.rb +14 -12
  25. data/lib/pagy/toolbox/helpers/bulma/input_nav_js.rb +14 -12
  26. data/lib/pagy/toolbox/helpers/bulma/previous_next_html.rb +15 -13
  27. data/lib/pagy/toolbox/helpers/bulma/series_nav.rb +21 -19
  28. data/lib/pagy/toolbox/helpers/bulma/series_nav_js.rb +13 -11
  29. data/lib/pagy/toolbox/helpers/info_tag.rb +23 -21
  30. data/lib/pagy/toolbox/helpers/input_nav_js.rb +12 -10
  31. data/lib/pagy/toolbox/helpers/limit_tag_js.rb +16 -14
  32. data/lib/pagy/toolbox/helpers/loaders.rb +55 -0
  33. data/lib/pagy/toolbox/helpers/series_nav.rb +21 -19
  34. data/lib/pagy/toolbox/helpers/series_nav_js.rb +12 -10
  35. data/lib/pagy/toolbox/helpers/support/a_lambda.rb +1 -1
  36. data/lib/pagy.rb +8 -3
  37. data/sig/pagy.rbs +312 -0
  38. metadata +3 -2
  39. data/lib/pagy/toolbox/helpers/loader.rb +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b91386444b1ca8b6cab6cc75caa70bb19d97247704b2eb2f5090bfcf7187fb49
4
- data.tar.gz: 102e7bdb7976cfdcbef5f8984fb8366d44f25e4f178f3bbe144aac5e91d51bcd
3
+ metadata.gz: e7117fd09b2c08ba0ecf14dd7d506d2f79e87729821a11b51c0009dc5cf1b748
4
+ data.tar.gz: 2067ac1fc8225d11ac841e8ef62ce976cd149fda4a04f17bd5e38d922e601f58
5
5
  SHA512:
6
- metadata.gz: 711efe91b6087d7447c84ec56dff02da4588e2005da9787bc6810b688f2d5481dca47a6be95f21eb8c6924291d93307a9e818931cc141f826408616e009568bd
7
- data.tar.gz: a5a068a430ba798a697c934bc59c9bc296dc669e0a94408a3226b258b9360489e131c90604311539e82294dd18a626342b7f5d14ad24b517ca8e01ae11edd296
6
+ metadata.gz: b9a10ad3940d5afaa7dc6a82a6d2a04ced413828a3bc11a3d4f25eb91994eae24b336efc3b3852486617d43b1231c680cc5f8f92dda271d9fa23f942a1087e04
7
+ data.tar.gz: ab3eeba7f94a578e23bbc1330a4b38a410f86f8021462f19f3be79f751f41f5634565c57152f13333a12c989de847972e35c7acf0c622fcc8f8cd97a21444200
data/apps/calendar.ru CHANGED
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.3.1'
19
+ VERSION = '43.3.2'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
data/apps/demo.ru CHANGED
@@ -19,7 +19,7 @@
19
19
  # URL
20
20
  # http://127.0.0.1:8000
21
21
 
22
- VERSION = '43.3.1'
22
+ VERSION = '43.3.2'
23
23
 
24
24
  if VERSION != Pagy::VERSION
25
25
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.3.1'
19
+ VERSION = '43.3.2'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
data/apps/keynav.ru CHANGED
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.3.1'
19
+ VERSION = '43.3.2'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
data/apps/keyset.ru CHANGED
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.3.1'
19
+ VERSION = '43.3.2'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.3.1'
19
+ VERSION = '43.3.2'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
data/apps/rails.ru CHANGED
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.3.1'
19
+ VERSION = '43.3.2'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
data/apps/repro.ru CHANGED
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.3.1'
19
+ VERSION = '43.3.2'
20
20
 
21
21
  if VERSION != Pagy::VERSION
22
22
  Warning.warn("\n>>> WARNING! '#{File.basename(__FILE__)}-#{VERSION}' running with 'pagy-#{Pagy::VERSION}'! <<< \n\n")
data/config/pagy.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Pagy initializer file (43.3.1)
3
+ # Pagy initializer file (43.3.2)
4
4
  # See https://ddnexus.github.io/pagy/resources/initializer/
5
5
 
6
6
  ############ Global Options ################################################################
data/javascripts/pagy.js CHANGED
@@ -129,7 +129,7 @@ window.Pagy = (() => {
129
129
  });
130
130
  };
131
131
  return {
132
- version: "43.3.1",
132
+ version: "43.3.2",
133
133
  init(arg) {
134
134
  const target = arg instanceof HTMLElement ? arg : document, elements = target.querySelectorAll("[data-pagy]");
135
135
  for (const element of elements) {
@@ -153,5 +153,5 @@ window.Pagy = (() => {
153
153
  };
154
154
  })();
155
155
 
156
- //# debugId=873B9EED9C5194DF64756E2164756E21
156
+ //# debugId=A1F1420FD13C520364756E2164756E21
157
157
  //# sourceMappingURL=pagy.js.map
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/pagy.ts"],
4
4
  "sourcesContent": [
5
- "interface SyncData {\n from?: number\n to?: number\n key: string\n str?: string\n}\ntype InitArgs = [\"k\", KeynavArgs] | // series_nav[_js] with keynav instance\n [\"snj\", SeriesNavJsArgs] | // series_nav_js\n [\"inj\", InputNavJsArgs] | // input_nav_js\n [\"ltj\", LimitTagJsArgs] // limit_tag_js\ntype AugmentKeynav = (nav:HTMLElement, keynavArgs:KeynavArgs) => Promise<((page: string) => string)>\ntype KeynavArgs = readonly [storageKey: string | null,\n rootKey: string | null,\n pageKey: string,\n last: number,\n spliceArgs?: SpliceArgs]\ntype SpliceArgs = readonly [start: number,\n deleteCount: number, // it would be optional, but ts complains\n ...items: Cutoff[]]\ntype Cutoff = readonly (string | number | boolean)[]\ntype AugmentedPage = [browserId: string,\n storageKey: string,\n pageNumber: number,\n pages: number,\n priorCutoff: Cutoff | null,\n pageCutoff: Cutoff | null]\ntype SeriesNavJsArgs = readonly [NavJsTokens, pageToken: string, NavJsSeries, KeynavArgs?]\ntype NavJsSeries = readonly [widths: number[],\n series: (string | number)[][],\n labels: string[][] | null]\ntype InputNavJsArgs = readonly [urlToken: string,\n pageToken: string,\n KeynavArgs?]\ntype LimitTagJsArgs = readonly [from: number,\n urlToken: string,\n pageToken: string,\n limitToken: string]\ntype NavJsTokens = readonly [before: string,\n anchor: string,\n current: string,\n gap: string,\n after: string]\ninterface NavJsElement extends HTMLElement {\n render(): void\n}\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst Pagy = (() => {\n const storageSupport = 'sessionStorage' in window && 'BroadcastChannel' in window;\n // eslint-disable-next-line prefer-const\n let pagy = \"pagy\", storage: Storage, sync: BroadcastChannel, tabId: number;\n if (storageSupport) {\n storage = sessionStorage; // shorten the compiled size\n sync = new BroadcastChannel(pagy);\n tabId = Date.now();\n // Sync the sessionStorage keys for the cutoffs opened in a new tab/window\n sync.addEventListener(\"message\", (e:MessageEvent<SyncData>) => {\n if (e.data.from) { // request cutoffs\n const cutoffs = storage.getItem(e.data.key);\n if (cutoffs) {\n sync.postMessage(<SyncData>{to: e.data.from, key: e.data.key, str: cutoffs});\n } // send response\n } else if (e.data.to) { // receive cutoffs\n if (e.data.to == tabId) {\n storage.setItem(e.data.key, <string>e.data.str);\n }\n }\n });\n }\n // The observer instance for responsive navs\n const rjsObserver = new ResizeObserver(\n entries => entries.forEach(e => {\n e.target.querySelectorAll<NavJsElement>(\".pagy-rjs\").forEach(el => el.render());\n }));\n\n /* Full set of B64 functions\n const B64Encode = (unicode:string) => btoa(String.fromCharCode(...(new TextEncoder).encode(unicode))),\n B64Safe = (unsafe:string) => unsafe.replace(/[+/=]/g, (m) => m == \"+\" ? \"-\" : m == \"/\" ? \"_\" : \"\"),\n B64SafeEncode = (unicode:string) => B64Safe(B64Encode(unicode)),\n B64Decode = (base64:string) => (new TextDecoder()).decode(Uint8Array.from(atob(base64), c => c.charCodeAt(0))),\n B64Unsafe = (safe:string) => safe.replace(/[-_]/g, (match) => match == \"-\" ? \"+\" : \"/\"),\n B64SafeDecode = (base64:string) => B64Decode(B64Unsafe(base64))\n */\n const B64SafeEncode = (unicode:string) => btoa(String.fromCharCode(...(new TextEncoder).encode(unicode)))\n .replace(/[+/=]/g, (m) => m == \"+\" ? \"-\" : m == \"/\" ? \"_\" : \"\"),\n B64Decode = (base64:string) => (new TextDecoder()).decode(Uint8Array.from(atob(base64), c => c.charCodeAt(0)));\n\n // Return a random key: 3 chars max, base-36 number < 36**3\n const randKey = () => Math.floor(Math.random() * 36 ** 3).toString(36);\n\n // Manage the page augmentation for Keynav, called only if storageSupport\n const augmentKeynav: AugmentKeynav = async (nav, [storageKey, rootKey, pageKey, last, spliceArgs]) => {\n let augmentPage:(page: string) => string;\n const browserKey = document.cookie.split(/;\\s+/) // it works even if malformed\n .find((row) => row.startsWith(pagy + \"=\"))\n ?.split(\"=\")[1] ?? randKey();\n document.cookie = pagy + \"=\" + browserKey; // Smaller .min size: set the cookie without checking\n if (storageKey && !(storageKey in storage)) {\n // Sync the sessiongStorage from other tabs/windows (e.g., open page in the new tab/window)\n sync.postMessage(<SyncData>{ from: tabId, key: storageKey });\n // Wait for the listener to copy the cutoffs in the current sessionStorage\n await new Promise<string|null>((resolve) => setTimeout(() => resolve(\"\"), 100));\n if (!(storageKey in storage)) { // the storageKey didn't get copied: fallback to countless pagination\n augmentPage = (page: string) => page + '+' + last;\n }\n }\n // @ts-expect-error If it is not assigned it means it supports keynav\n if (!augmentPage) { // regular keynav pagination\n if (!storageKey) { do { storageKey = randKey() } while (storageKey in storage) } // no dup keys\n const data = storage.getItem(storageKey),\n cutoffs = <Cutoff[]>(data ? JSON.parse(data) : [undefined]);\n if (spliceArgs) {\n cutoffs.splice(...spliceArgs);\n storage.setItem(storageKey, JSON.stringify(cutoffs));\n }\n // Augment function\n augmentPage = (page:string) => {\n const pageNum = parseInt(page);\n return B64SafeEncode(JSON.stringify(\n <AugmentedPage>[browserKey,\n storageKey,\n pageNum,\n cutoffs.length, // pages/last\n cutoffs[pageNum - 1], // priorCutoff\n cutoffs[pageNum]])); // pageCutoff\n };\n }\n const search = (rootKey) ? `${rootKey}%5B${pageKey}%5D` : pageKey;\n const re = new RegExp(`(?<=\\\\?.*)(\\\\b${search}=)(\\\\d+)`);\n // Augment the page param of each href\n for (const a of <NodeListOf<HTMLAnchorElement>><unknown>nav.querySelectorAll('a[href]')) {\n a.href = a.href.replace(re, (_match, prefix, digit): string => `${prefix}${augmentPage(<string>digit)}`);\n }\n // Return the augment function for further augmentation (i.e., url token in input_nav_js)\n return augmentPage;\n };\n\n // Build the series_nav_js helper\n const buildNavJs = (nav:NavJsElement, [[before, anchor, current, gap, after], pageToken,\n [widths, series, labels], keynavArgs]:SeriesNavJsArgs) => {\n const parent = <HTMLElement>nav.parentElement;\n let lastWidth = -1;\n (nav.render = () => {\n const index = widths.findIndex(w => w < parent.clientWidth);\n if (widths[index] === lastWidth) { return } // no change: abort\n\n let html = before;\n series[index].forEach((item, i) => {\n // Avoid the if blocks and chain the results (shorter pagy.min.js and easier reading)\n html += item == \"gap\" ? gap :\n // @ts-expect-error the item may be a number, but the 'replace' converts it to string (shorter pagy.min.js)\n (typeof item == \"number\" ? anchor.replace(pageToken, item) : current)\n .replace(\"L<\", labels?.[index][i] ?? item + \"<\");\n });\n html += after;\n nav.innerHTML = \"\";\n nav.insertAdjacentHTML(\"afterbegin\", html);\n lastWidth = widths[index];\n if (keynavArgs && storageSupport) { void augmentKeynav(nav, keynavArgs) }\n })();\n if (nav.classList.contains(pagy + \"-rjs\")) { rjsObserver.observe(parent) }\n };\n\n // Init the input_nav_js helpers\n const initInputNavJs = async (nav:HTMLElement, [url_token, pageToken, keynavArgs]:InputNavJsArgs) => {\n const augment = keynavArgs && storageSupport\n ? await augmentKeynav(nav, keynavArgs)\n : (page: string) => page;\n initInput(nav, inputValue => url_token.replace(pageToken, augment(inputValue)));\n };\n\n // Init the limit_tag_js helper\n const initLimitTagJs = (span:HTMLSpanElement, [from, url_token, page_token, limitToken]:LimitTagJsArgs) => {\n initInput(span, inputValue => {\n // @ts-expect-error the page is a number, but the 'replace' converts it to string (shorter pagy.min.js)\n return url_token.replace(page_token, Math.max(Math.ceil(from / parseInt(inputValue)), 1))\n .replace(limitToken, inputValue);\n });\n };\n\n // Init the input element\n const initInput = (element:HTMLElement, getUrl:(v:string) => string) => {\n const input = <HTMLInputElement>element.querySelector(\"input\"),\n link = <HTMLAnchorElement>element.querySelector(\"a\");\n let initial = input.value;\n const action = () => {\n if (input.value === initial) { return } // not changed\n const [min, val, max] = [input.min, input.value, input.max].map(n => parseInt(n) || 0);\n if (val < min || val > max) { // reset invalid/out-of-range\n input.value = initial;\n input.select();\n return;\n }\n initial = input.value;\n link.href = getUrl(input.value);\n link.click();\n };\n input.addEventListener(\"focus\", () => input.select());\n input.addEventListener(\"focusout\", action);\n input.addEventListener(\"keypress\", e => { if (e.key == \"Enter\") { action() } });\n };\n\n // Public interface\n return {\n version: \"43.3.1\",\n\n // Scan for elements with a \"data-pagy\" attribute and call their init functions with the decoded args\n init(arg?:HTMLElement) {\n const target = arg instanceof HTMLElement ? arg : document,\n elements = target.querySelectorAll(\"[data-pagy]\");\n for (const element of <NodeListOf<HTMLElement>>elements) {\n try {\n const [helperId, ...args] = <InitArgs>JSON.parse(B64Decode(<string>element.getAttribute(\"data-pagy\")));\n if (helperId == \"k\") {\n // @ts-expect-error spread 2 arguments, not 3 as it complains about\n void augmentKeynav(element, ...<KeynavArgs><unknown>args);\n } else if (helperId == \"snj\") {\n buildNavJs(<NavJsElement>element, <SeriesNavJsArgs><unknown>args);\n } else if (helperId == \"inj\") {\n void initInputNavJs(element, <InputNavJsArgs><unknown>args);\n } else if (helperId == \"ltj\") {\n initLimitTagJs(element, <LimitTagJsArgs><unknown>args);\n }\n // else { console.warn(\"Pagy.init: %o\\nUnknown helperId '%s'\", element, helperId) }\n } catch (err) { console.warn(\"Pagy.init: %o\\n%s\", element, err) }\n }\n }\n };\n})();\n"
5
+ "interface SyncData {\n from?: number\n to?: number\n key: string\n str?: string\n}\ntype InitArgs = [\"k\", KeynavArgs] | // series_nav[_js] with keynav instance\n [\"snj\", SeriesNavJsArgs] | // series_nav_js\n [\"inj\", InputNavJsArgs] | // input_nav_js\n [\"ltj\", LimitTagJsArgs] // limit_tag_js\ntype AugmentKeynav = (nav:HTMLElement, keynavArgs:KeynavArgs) => Promise<((page: string) => string)>\ntype KeynavArgs = readonly [storageKey: string | null,\n rootKey: string | null,\n pageKey: string,\n last: number,\n spliceArgs?: SpliceArgs]\ntype SpliceArgs = readonly [start: number,\n deleteCount: number, // it would be optional, but ts complains\n ...items: Cutoff[]]\ntype Cutoff = readonly (string | number | boolean)[]\ntype AugmentedPage = [browserId: string,\n storageKey: string,\n pageNumber: number,\n pages: number,\n priorCutoff: Cutoff | null,\n pageCutoff: Cutoff | null]\ntype SeriesNavJsArgs = readonly [NavJsTokens, pageToken: string, NavJsSeries, KeynavArgs?]\ntype NavJsSeries = readonly [widths: number[],\n series: (string | number)[][],\n labels: string[][] | null]\ntype InputNavJsArgs = readonly [urlToken: string,\n pageToken: string,\n KeynavArgs?]\ntype LimitTagJsArgs = readonly [from: number,\n urlToken: string,\n pageToken: string,\n limitToken: string]\ntype NavJsTokens = readonly [before: string,\n anchor: string,\n current: string,\n gap: string,\n after: string]\ninterface NavJsElement extends HTMLElement {\n render(): void\n}\n\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nconst Pagy = (() => {\n const storageSupport = 'sessionStorage' in window && 'BroadcastChannel' in window;\n // eslint-disable-next-line prefer-const\n let pagy = \"pagy\", storage: Storage, sync: BroadcastChannel, tabId: number;\n if (storageSupport) {\n storage = sessionStorage; // shorten the compiled size\n sync = new BroadcastChannel(pagy);\n tabId = Date.now();\n // Sync the sessionStorage keys for the cutoffs opened in a new tab/window\n sync.addEventListener(\"message\", (e:MessageEvent<SyncData>) => {\n if (e.data.from) { // request cutoffs\n const cutoffs = storage.getItem(e.data.key);\n if (cutoffs) {\n sync.postMessage(<SyncData>{to: e.data.from, key: e.data.key, str: cutoffs});\n } // send response\n } else if (e.data.to) { // receive cutoffs\n if (e.data.to == tabId) {\n storage.setItem(e.data.key, <string>e.data.str);\n }\n }\n });\n }\n // The observer instance for responsive navs\n const rjsObserver = new ResizeObserver(\n entries => entries.forEach(e => {\n e.target.querySelectorAll<NavJsElement>(\".pagy-rjs\").forEach(el => el.render());\n }));\n\n /* Full set of B64 functions\n const B64Encode = (unicode:string) => btoa(String.fromCharCode(...(new TextEncoder).encode(unicode))),\n B64Safe = (unsafe:string) => unsafe.replace(/[+/=]/g, (m) => m == \"+\" ? \"-\" : m == \"/\" ? \"_\" : \"\"),\n B64SafeEncode = (unicode:string) => B64Safe(B64Encode(unicode)),\n B64Decode = (base64:string) => (new TextDecoder()).decode(Uint8Array.from(atob(base64), c => c.charCodeAt(0))),\n B64Unsafe = (safe:string) => safe.replace(/[-_]/g, (match) => match == \"-\" ? \"+\" : \"/\"),\n B64SafeDecode = (base64:string) => B64Decode(B64Unsafe(base64))\n */\n const B64SafeEncode = (unicode:string) => btoa(String.fromCharCode(...(new TextEncoder).encode(unicode)))\n .replace(/[+/=]/g, (m) => m == \"+\" ? \"-\" : m == \"/\" ? \"_\" : \"\"),\n B64Decode = (base64:string) => (new TextDecoder()).decode(Uint8Array.from(atob(base64), c => c.charCodeAt(0)));\n\n // Return a random key: 3 chars max, base-36 number < 36**3\n const randKey = () => Math.floor(Math.random() * 36 ** 3).toString(36);\n\n // Manage the page augmentation for Keynav, called only if storageSupport\n const augmentKeynav: AugmentKeynav = async (nav, [storageKey, rootKey, pageKey, last, spliceArgs]) => {\n let augmentPage:(page: string) => string;\n const browserKey = document.cookie.split(/;\\s+/) // it works even if malformed\n .find((row) => row.startsWith(pagy + \"=\"))\n ?.split(\"=\")[1] ?? randKey();\n document.cookie = pagy + \"=\" + browserKey; // Smaller .min size: set the cookie without checking\n if (storageKey && !(storageKey in storage)) {\n // Sync the sessiongStorage from other tabs/windows (e.g., open page in the new tab/window)\n sync.postMessage(<SyncData>{ from: tabId, key: storageKey });\n // Wait for the listener to copy the cutoffs in the current sessionStorage\n await new Promise<string|null>((resolve) => setTimeout(() => resolve(\"\"), 100));\n if (!(storageKey in storage)) { // the storageKey didn't get copied: fallback to countless pagination\n augmentPage = (page: string) => page + '+' + last;\n }\n }\n // @ts-expect-error If it is not assigned it means it supports keynav\n if (!augmentPage) { // regular keynav pagination\n if (!storageKey) { do { storageKey = randKey() } while (storageKey in storage) } // no dup keys\n const data = storage.getItem(storageKey),\n cutoffs = <Cutoff[]>(data ? JSON.parse(data) : [undefined]);\n if (spliceArgs) {\n cutoffs.splice(...spliceArgs);\n storage.setItem(storageKey, JSON.stringify(cutoffs));\n }\n // Augment function\n augmentPage = (page:string) => {\n const pageNum = parseInt(page);\n return B64SafeEncode(JSON.stringify(\n <AugmentedPage>[browserKey,\n storageKey,\n pageNum,\n cutoffs.length, // pages/last\n cutoffs[pageNum - 1], // priorCutoff\n cutoffs[pageNum]])); // pageCutoff\n };\n }\n const search = (rootKey) ? `${rootKey}%5B${pageKey}%5D` : pageKey;\n const re = new RegExp(`(?<=\\\\?.*)(\\\\b${search}=)(\\\\d+)`);\n // Augment the page param of each href\n for (const a of <NodeListOf<HTMLAnchorElement>><unknown>nav.querySelectorAll('a[href]')) {\n a.href = a.href.replace(re, (_match, prefix, digit): string => `${prefix}${augmentPage(<string>digit)}`);\n }\n // Return the augment function for further augmentation (i.e., url token in input_nav_js)\n return augmentPage;\n };\n\n // Build the series_nav_js helper\n const buildNavJs = (nav:NavJsElement, [[before, anchor, current, gap, after], pageToken,\n [widths, series, labels], keynavArgs]:SeriesNavJsArgs) => {\n const parent = <HTMLElement>nav.parentElement;\n let lastWidth = -1;\n (nav.render = () => {\n const index = widths.findIndex(w => w < parent.clientWidth);\n if (widths[index] === lastWidth) { return } // no change: abort\n\n let html = before;\n series[index].forEach((item, i) => {\n // Avoid the if blocks and chain the results (shorter pagy.min.js and easier reading)\n html += item == \"gap\" ? gap :\n // @ts-expect-error the item may be a number, but the 'replace' converts it to string (shorter pagy.min.js)\n (typeof item == \"number\" ? anchor.replace(pageToken, item) : current)\n .replace(\"L<\", labels?.[index][i] ?? item + \"<\");\n });\n html += after;\n nav.innerHTML = \"\";\n nav.insertAdjacentHTML(\"afterbegin\", html);\n lastWidth = widths[index];\n if (keynavArgs && storageSupport) { void augmentKeynav(nav, keynavArgs) }\n })();\n if (nav.classList.contains(pagy + \"-rjs\")) { rjsObserver.observe(parent) }\n };\n\n // Init the input_nav_js helpers\n const initInputNavJs = async (nav:HTMLElement, [url_token, pageToken, keynavArgs]:InputNavJsArgs) => {\n const augment = keynavArgs && storageSupport\n ? await augmentKeynav(nav, keynavArgs)\n : (page: string) => page;\n initInput(nav, inputValue => url_token.replace(pageToken, augment(inputValue)));\n };\n\n // Init the limit_tag_js helper\n const initLimitTagJs = (span:HTMLSpanElement, [from, url_token, page_token, limitToken]:LimitTagJsArgs) => {\n initInput(span, inputValue => {\n // @ts-expect-error the page is a number, but the 'replace' converts it to string (shorter pagy.min.js)\n return url_token.replace(page_token, Math.max(Math.ceil(from / parseInt(inputValue)), 1))\n .replace(limitToken, inputValue);\n });\n };\n\n // Init the input element\n const initInput = (element:HTMLElement, getUrl:(v:string) => string) => {\n const input = <HTMLInputElement>element.querySelector(\"input\"),\n link = <HTMLAnchorElement>element.querySelector(\"a\");\n let initial = input.value;\n const action = () => {\n if (input.value === initial) { return } // not changed\n const [min, val, max] = [input.min, input.value, input.max].map(n => parseInt(n) || 0);\n if (val < min || val > max) { // reset invalid/out-of-range\n input.value = initial;\n input.select();\n return;\n }\n initial = input.value;\n link.href = getUrl(input.value);\n link.click();\n };\n input.addEventListener(\"focus\", () => input.select());\n input.addEventListener(\"focusout\", action);\n input.addEventListener(\"keypress\", e => { if (e.key == \"Enter\") { action() } });\n };\n\n // Public interface\n return {\n version: \"43.3.2\",\n\n // Scan for elements with a \"data-pagy\" attribute and call their init functions with the decoded args\n init(arg?:HTMLElement) {\n const target = arg instanceof HTMLElement ? arg : document,\n elements = target.querySelectorAll(\"[data-pagy]\");\n for (const element of <NodeListOf<HTMLElement>>elements) {\n try {\n const [helperId, ...args] = <InitArgs>JSON.parse(B64Decode(<string>element.getAttribute(\"data-pagy\")));\n if (helperId == \"k\") {\n // @ts-expect-error spread 2 arguments, not 3 as it complains about\n void augmentKeynav(element, ...<KeynavArgs><unknown>args);\n } else if (helperId == \"snj\") {\n buildNavJs(<NavJsElement>element, <SeriesNavJsArgs><unknown>args);\n } else if (helperId == \"inj\") {\n void initInputNavJs(element, <InputNavJsArgs><unknown>args);\n } else if (helperId == \"ltj\") {\n initLimitTagJs(element, <LimitTagJsArgs><unknown>args);\n }\n // else { console.warn(\"Pagy.init: %o\\nUnknown helperId '%s'\", element, helperId) }\n } catch (err) { console.warn(\"Pagy.init: %o\\n%s\", element, err) }\n }\n }\n };\n})();\n"
6
6
  ],
7
7
  "mappings": "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",
8
- "debugId": "873B9EED9C5194DF64756E2164756E21",
8
+ "debugId": "A1F1420FD13C520364756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,2 +1,2 @@
1
- window.Pagy=(()=>{let B="sessionStorage"in window&&"BroadcastChannel"in window,L="pagy",Z,O,W;if(B)Z=sessionStorage,O=new BroadcastChannel(L),W=Date.now(),O.addEventListener("message",(q)=>{if(q.data.from){let z=Z.getItem(q.data.key);if(z)O.postMessage({to:q.data.from,key:q.data.key,str:z})}else if(q.data.to){if(q.data.to==W)Z.setItem(q.data.key,q.data.str)}});let P=new ResizeObserver((q)=>q.forEach((z)=>{z.target.querySelectorAll(".pagy-rjs").forEach((C)=>C.render())})),V=(q)=>btoa(String.fromCharCode(...new TextEncoder().encode(q))).replace(/[+/=]/g,(z)=>z=="+"?"-":z=="/"?"_":""),_=(q)=>new TextDecoder().decode(Uint8Array.from(atob(q),(z)=>z.charCodeAt(0))),S=()=>Math.floor(Math.random()*46656).toString(36),J=async(q,[z,C,F,H,G])=>{let Q,X=document.cookie.split(/;\s+/).find((M)=>M.startsWith(L+"="))?.split("=")[1]??S();if(document.cookie=L+"="+X,z&&!(z in Z)){if(O.postMessage({from:W,key:z}),await new Promise((M)=>setTimeout(()=>M(""),100)),!(z in Z))Q=(M)=>M+"+"+H}if(!Q){if(!z)do z=S();while(z in Z);let M=Z.getItem(z),Y=M?JSON.parse(M):[void 0];if(G)Y.splice(...G),Z.setItem(z,JSON.stringify(Y));Q=($)=>{let R=parseInt($);return V(JSON.stringify([X,z,R,Y.length,Y[R-1],Y[R]]))}}let D=C?`${C}%5B${F}%5D`:F,E=new RegExp(`(?<=\\?.*)(\\b${D}=)(\\d+)`);for(let M of q.querySelectorAll("a[href]"))M.href=M.href.replace(E,(Y,$,R)=>`${$}${Q(R)}`);return Q},x=(q,[[z,C,F,H,G],Q,[X,D,E],M])=>{let Y=q.parentElement,$=-1;if((q.render=()=>{let R=X.findIndex((j)=>j<Y.clientWidth);if(X[R]===$)return;let U=z;if(D[R].forEach((j,I)=>{U+=j=="gap"?H:(typeof j=="number"?C.replace(Q,j):F).replace("L<",E?.[R][I]??j+"<")}),U+=G,q.innerHTML="",q.insertAdjacentHTML("afterbegin",U),$=X[R],M&&B)J(q,M)})(),q.classList.contains(L+"-rjs"))P.observe(Y)},T=async(q,[z,C,F])=>{let H=F&&B?await J(q,F):(G)=>G;N(q,(G)=>z.replace(C,H(G)))},A=(q,[z,C,F,H])=>{N(q,(G)=>{return C.replace(F,Math.max(Math.ceil(z/parseInt(G)),1)).replace(H,G)})},N=(q,z)=>{let C=q.querySelector("input"),F=q.querySelector("a"),H=C.value,G=()=>{if(C.value===H)return;let[Q,X,D]=[C.min,C.value,C.max].map((E)=>parseInt(E)||0);if(X<Q||X>D){C.value=H,C.select();return}H=C.value,F.href=z(C.value),F.click()};C.addEventListener("focus",()=>C.select()),C.addEventListener("focusout",G),C.addEventListener("keypress",(Q)=>{if(Q.key=="Enter")G()})};return{version:"43.3.1",init(q){let z=q instanceof HTMLElement?q:document,C=z.querySelectorAll("[data-pagy]");for(let F of C)try{let[H,...G]=JSON.parse(_(F.getAttribute("data-pagy")));if(H=="k")J(F,...G);else if(H=="snj")x(F,G);else if(H=="inj")T(F,G);else if(H=="ltj")A(F,G)}catch(H){console.warn(`Pagy.init: %o
1
+ window.Pagy=(()=>{let B="sessionStorage"in window&&"BroadcastChannel"in window,L="pagy",Z,O,W;if(B)Z=sessionStorage,O=new BroadcastChannel(L),W=Date.now(),O.addEventListener("message",(q)=>{if(q.data.from){let z=Z.getItem(q.data.key);if(z)O.postMessage({to:q.data.from,key:q.data.key,str:z})}else if(q.data.to){if(q.data.to==W)Z.setItem(q.data.key,q.data.str)}});let P=new ResizeObserver((q)=>q.forEach((z)=>{z.target.querySelectorAll(".pagy-rjs").forEach((C)=>C.render())})),V=(q)=>btoa(String.fromCharCode(...new TextEncoder().encode(q))).replace(/[+/=]/g,(z)=>z=="+"?"-":z=="/"?"_":""),_=(q)=>new TextDecoder().decode(Uint8Array.from(atob(q),(z)=>z.charCodeAt(0))),S=()=>Math.floor(Math.random()*46656).toString(36),J=async(q,[z,C,F,H,G])=>{let Q,X=document.cookie.split(/;\s+/).find((M)=>M.startsWith(L+"="))?.split("=")[1]??S();if(document.cookie=L+"="+X,z&&!(z in Z)){if(O.postMessage({from:W,key:z}),await new Promise((M)=>setTimeout(()=>M(""),100)),!(z in Z))Q=(M)=>M+"+"+H}if(!Q){if(!z)do z=S();while(z in Z);let M=Z.getItem(z),Y=M?JSON.parse(M):[void 0];if(G)Y.splice(...G),Z.setItem(z,JSON.stringify(Y));Q=($)=>{let R=parseInt($);return V(JSON.stringify([X,z,R,Y.length,Y[R-1],Y[R]]))}}let D=C?`${C}%5B${F}%5D`:F,E=new RegExp(`(?<=\\?.*)(\\b${D}=)(\\d+)`);for(let M of q.querySelectorAll("a[href]"))M.href=M.href.replace(E,(Y,$,R)=>`${$}${Q(R)}`);return Q},x=(q,[[z,C,F,H,G],Q,[X,D,E],M])=>{let Y=q.parentElement,$=-1;if((q.render=()=>{let R=X.findIndex((j)=>j<Y.clientWidth);if(X[R]===$)return;let U=z;if(D[R].forEach((j,I)=>{U+=j=="gap"?H:(typeof j=="number"?C.replace(Q,j):F).replace("L<",E?.[R][I]??j+"<")}),U+=G,q.innerHTML="",q.insertAdjacentHTML("afterbegin",U),$=X[R],M&&B)J(q,M)})(),q.classList.contains(L+"-rjs"))P.observe(Y)},T=async(q,[z,C,F])=>{let H=F&&B?await J(q,F):(G)=>G;N(q,(G)=>z.replace(C,H(G)))},A=(q,[z,C,F,H])=>{N(q,(G)=>{return C.replace(F,Math.max(Math.ceil(z/parseInt(G)),1)).replace(H,G)})},N=(q,z)=>{let C=q.querySelector("input"),F=q.querySelector("a"),H=C.value,G=()=>{if(C.value===H)return;let[Q,X,D]=[C.min,C.value,C.max].map((E)=>parseInt(E)||0);if(X<Q||X>D){C.value=H,C.select();return}H=C.value,F.href=z(C.value),F.click()};C.addEventListener("focus",()=>C.select()),C.addEventListener("focusout",G),C.addEventListener("keypress",(Q)=>{if(Q.key=="Enter")G()})};return{version:"43.3.2",init(q){let z=q instanceof HTMLElement?q:document,C=z.querySelectorAll("[data-pagy]");for(let F of C)try{let[H,...G]=JSON.parse(_(F.getAttribute("data-pagy")));if(H=="k")J(F,...G);else if(H=="snj")x(F,G);else if(H=="inj")T(F,G);else if(H=="ltj")A(F,G)}catch(H){console.warn(`Pagy.init: %o
2
2
  %s`,F,H)}}}})();
data/javascripts/pagy.mjs CHANGED
@@ -128,7 +128,7 @@ const Pagy = (() => {
128
128
  });
129
129
  };
130
130
  return {
131
- version: "43.3.1",
131
+ version: "43.3.2",
132
132
  init(arg) {
133
133
  const target = arg instanceof HTMLElement ? arg : document, elements = target.querySelectorAll("[data-pagy]");
134
134
  for (const element of elements) {
@@ -16,6 +16,7 @@ class Pagy
16
16
 
17
17
  include Rangeable
18
18
  include Shiftable
19
+ include NumericHelpers
19
20
 
20
21
  def initialize(**)
21
22
  assign_options(**)
@@ -7,8 +7,8 @@ class Pagy
7
7
  module ActiveRecord
8
8
  # Extract the keyset from the set
9
9
  def extract_keyset
10
- @set.order_values.each_with_object({}) do |node, keyset|
11
- keyset[node.value.name.to_sym] = node.direction
10
+ @set.order_values.to_h do |node|
11
+ [node.value.name.to_sym, node.direction]
12
12
  end
13
13
  end
14
14
 
@@ -13,6 +13,8 @@ class Pagy
13
13
  class ActiveRecord < self; end
14
14
  class Sequel < self; end
15
15
 
16
+ include NumericHelpers
17
+
16
18
  # Finalize the instance variables needed for the UI
17
19
  def initialize(set, **)
18
20
  super
@@ -13,6 +13,7 @@ class Pagy
13
13
 
14
14
  include Rangeable
15
15
  include Shiftable
16
+ include NumericHelpers
16
17
 
17
18
  def initialize(**)
18
19
  assign_options(**)
@@ -32,7 +33,7 @@ class Pagy
32
33
  assign_previous_and_next
33
34
  end
34
35
 
35
- attr_reader :offset, :count, :from, :to, :in, :previous, :last
36
+ attr_reader :offset, :count, :from, :to, :in, :previous, :next, :last
36
37
  alias pages last
37
38
 
38
39
  def records(collection)
@@ -52,17 +52,17 @@ class Pagy
52
52
  p11n = dictionary['pagy'].delete('p11n')
53
53
  raise KeyError, "missing 'p11n' key in #{locale.inspect} locale" unless p11n
54
54
 
55
- locales[locale] = [flatten_to_dot_keys(dictionary), Object.const_get("Pagy::I18n::P11n::#{p11n}")]
55
+ locales[locale] = [dotify_keys(dictionary), Object.const_get("Pagy::I18n::P11n::#{p11n}")]
56
56
  end
57
57
 
58
- # Create a flat hash with dotted notation keys
58
+ # Flatten a nested hash by "dotifying" its keys
59
59
  # e.g. { 'a' => { 'b' => {'c' => 3, 'd' => 4 }}} -> { 'a.b.c' => 3, 'a.b.d' => 4 }
60
- def flatten_to_dot_keys(initial, prefix = '')
60
+ def dotify_keys(initial, prefix = '')
61
61
  initial.each_with_object({}) do |(key, value), hash|
62
62
  key = "#{prefix}#{key}"
63
63
 
64
64
  if value.is_a?(Hash)
65
- hash.merge!(flatten_to_dot_keys(value, "#{key}."))
65
+ hash.merge!(dotify_keys(value, "#{key}."))
66
66
  else
67
67
  hash[key] = value
68
68
  end
@@ -3,8 +3,10 @@
3
3
  require_relative 'support/a_lambda' # inheritable
4
4
 
5
5
  class Pagy
6
- # Return the enabled/disabled previous page anchor tag
7
- def previous_tag(...) = anchor_tag_for(:previous, ...)
6
+ module NumericHelpers
7
+ # Return the enabled/disabled previous page anchor tag
8
+ def previous_tag(...) = anchor_tag_for(:previous, ...)
9
+ end
8
10
 
9
11
  # Return the enabled/disabled next page anchor tag
10
12
  def next_tag(...) = anchor_tag_for(:next, ...)
@@ -14,8 +16,8 @@ class Pagy
14
16
  def anchor_tag_for(which, a = nil, text: I18n.translate("pagy.#{which}"),
15
17
  aria_label: I18n.translate("pagy.aria_label.#{which}"), **)
16
18
  page = send(which)
17
- return (a || a_lambda(**)).(page.to_i, text, aria_label:) if page
19
+ return %(<a role="link" aria-disabled="true" aria-label="#{aria_label}">#{text}</a>) unless page
18
20
 
19
- %(<a role="link" aria-disabled="true" aria-label="#{aria_label}">#{text}</a>)
21
+ (a || a_lambda(**)).(page, text, aria_label:)
20
22
  end
21
23
  end
@@ -4,24 +4,26 @@ require_relative 'previous_next_html'
4
4
  require_relative '../support/wrap_input_nav_js'
5
5
 
6
6
  class Pagy
7
- private
7
+ module NumericHelpers
8
+ private
8
9
 
9
- # Javascript combo pagination for bootstrap: it returns a nav with a data-pagy attribute used by the pagy.js file
10
- def bootstrap_input_nav_js(classes: 'pagination', **)
11
- a_lambda = a_lambda(**)
10
+ # Javascript combo pagination for bootstrap: it returns a nav with a data-pagy attribute used by the pagy.js file
11
+ def bootstrap_input_nav_js(classes: 'pagination', **)
12
+ a_lambda = a_lambda(**)
12
13
 
13
- input = %(<input name="page" type="number" min="1" max="#{last}" value="#{@page}" aria-current="page" ) +
14
- %(style="text-align: center; width: #{@page.to_s.length + 1}rem; padding: 0; border-radius: .25rem; ) +
15
- %(border: none; display: inline-block;" class="page-link active">#{A_TAG})
14
+ input = %(<input name="page" type="number" min="1" max="#{last}" value="#{@page}" aria-current="page" ) +
15
+ %(style="text-align: center; width: #{@page.to_s.length + 1}rem; padding: 0; border-radius: .25rem; ) +
16
+ %(border: none; display: inline-block;" class="page-link active">#{A_TAG})
16
17
 
17
- html = %(<ul class="#{classes}">#{
18
- bootstrap_html_for(:previous, a_lambda)
19
- }<li class="page-item"><label class="page-link">#{
20
- I18n.translate('pagy.input_nav_js', page_input: input, pages: @last)
21
- }</label></li>#{
22
- bootstrap_html_for(:next, a_lambda)
23
- }</ul>)
18
+ html = %(<ul class="#{classes}">#{
19
+ bootstrap_html_for(:previous, a_lambda)
20
+ }<li class="page-item"><label class="page-link">#{
21
+ I18n.translate('pagy.input_nav_js', page_input: input, pages: @last)
22
+ }</label></li>#{
23
+ bootstrap_html_for(:next, a_lambda)
24
+ }</ul>)
24
25
 
25
- wrap_input_nav_js(html, 'pagy-bootstrap input-nav-js', **)
26
+ wrap_input_nav_js(html, 'pagy-bootstrap input-nav-js', **)
27
+ end
26
28
  end
27
29
  end
@@ -1,18 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Pagy
4
- private
4
+ module NumericHelpers
5
+ private
5
6
 
6
- # Return the enabled/disabled previous/next page anchor tag, embedded in the li tag
7
- def bootstrap_html_for(which, a_lambda)
8
- if send(which)
9
- %(<li class="page-item #{which}">#{
10
- a_lambda.(send(which), I18n.translate("pagy.#{which}"),
11
- classes: 'page-link',
12
- aria_label: I18n.translate("pagy.aria_label.#{which}"))}</li>)
13
- else
14
- %(<li class="page-item #{which} disabled"><a role="link" class="page-link" aria-disabled="true" aria-label="#{
15
- I18n.translate("pagy.aria_label.#{which}")}">#{I18n.translate("pagy.#{which}")}</a></li>)
7
+ # Return the enabled/disabled previous/next page anchor tag, embedded in the li tag
8
+ def bootstrap_html_for(which, a_lambda)
9
+ if send(which)
10
+ %(<li class="page-item #{which}">#{
11
+ a_lambda.(send(which), I18n.translate("pagy.#{which}"),
12
+ classes: 'page-link',
13
+ aria_label: I18n.translate("pagy.aria_label.#{which}"))}</li>)
14
+ else
15
+ %(<li class="page-item #{which} disabled"><a role="link" class="page-link" aria-disabled="true" aria-label="#{
16
+ I18n.translate("pagy.aria_label.#{which}")}">#{I18n.translate("pagy.#{which}")}</a></li>)
17
+ end
16
18
  end
17
19
  end
18
20
  end
@@ -4,28 +4,30 @@ require_relative 'previous_next_html'
4
4
  require_relative '../support/wrap_series_nav'
5
5
 
6
6
  class Pagy
7
- private
7
+ module NumericHelpers
8
+ private
8
9
 
9
- # Pagination for bootstrap: it returns the html with the series of links to the pages
10
- def bootstrap_series_nav(classes: 'pagination', **)
11
- a_lambda = a_lambda(**)
10
+ # Pagination for bootstrap: it returns the html with the series of links to the pages
11
+ def bootstrap_series_nav(classes: 'pagination', **)
12
+ a_lambda = a_lambda(**)
12
13
 
13
- html = %(<ul class="#{classes}">#{bootstrap_html_for(:previous, a_lambda)})
14
- series(**).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
15
- html << case item
16
- when Integer
17
- %(<li class="page-item">#{a_lambda.(item, classes: 'page-link')}</li>)
18
- when String
19
- %(<li class="page-item active"><a role="link" class="page-link" aria-current="page" aria-disabled="true">#{
20
- page_label(item)}</a></li>)
21
- when :gap
22
- %(<li class="page-item gap disabled"><a role="link" class="page-link" aria-disabled="true">#{
23
- I18n.translate('pagy.gap')}</a></li>)
24
- else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
25
- end
26
- end
27
- html << %(#{bootstrap_html_for(:next, a_lambda)}</ul>)
14
+ html = %(<ul class="#{classes}">#{bootstrap_html_for(:previous, a_lambda)})
15
+ series(**).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
16
+ html << case item
17
+ when Integer
18
+ %(<li class="page-item">#{a_lambda.(item, classes: 'page-link')}</li>)
19
+ when String
20
+ %(<li class="page-item active"><a role="link" class="page-link" aria-current="page" aria-disabled="true">#{
21
+ page_label(item)}</a></li>)
22
+ when :gap
23
+ %(<li class="page-item gap disabled"><a role="link" class="page-link" aria-disabled="true">#{
24
+ I18n.translate('pagy.gap')}</a></li>)
25
+ else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
26
+ end
27
+ end
28
+ html << %(#{bootstrap_html_for(:next, a_lambda)}</ul>)
28
29
 
29
- wrap_series_nav(html, 'pagy-bootstrap series-nav', **)
30
+ wrap_series_nav(html, 'pagy-bootstrap series-nav', **)
31
+ end
30
32
  end
31
33
  end
@@ -4,20 +4,22 @@ require_relative 'previous_next_html'
4
4
  require_relative '../support/wrap_series_nav_js'
5
5
 
6
6
  class Pagy
7
- private
7
+ module NumericHelpers
8
+ private
8
9
 
9
- # Javascript pagination for bootstrap: it returns a nav with a data-pagy attribute used by the pagy.js file
10
- def bootstrap_series_nav_js(classes: 'pagination', **)
11
- a_lambda = a_lambda(**)
10
+ # Javascript pagination for bootstrap: it returns a nav with a data-pagy attribute used by the pagy.js file
11
+ def bootstrap_series_nav_js(classes: 'pagination', **)
12
+ a_lambda = a_lambda(**)
12
13
 
13
- tokens = { before: %(<ul class="#{classes}">#{bootstrap_html_for(:previous, a_lambda)}),
14
- anchor: %(<li class="page-item">#{a_lambda.(PAGE_TOKEN, LABEL_TOKEN, classes: 'page-link')}</li>),
15
- current: %(<li class="page-item active"><a role="link" class="page-link" ) +
16
- %(aria-current="page" aria-disabled="true">#{LABEL_TOKEN}</a></li>),
17
- gap: %(<li class="page-item gap disabled"><a role="link" class="page-link" aria-disabled="true">#{
18
- I18n.translate('pagy.gap')}</a></li>),
19
- after: %(#{bootstrap_html_for(:next, a_lambda)}</ul>) }
14
+ tokens = { before: %(<ul class="#{classes}">#{bootstrap_html_for(:previous, a_lambda)}),
15
+ anchor: %(<li class="page-item">#{a_lambda.(PAGE_TOKEN, LABEL_TOKEN, classes: 'page-link')}</li>),
16
+ current: %(<li class="page-item active"><a role="link" class="page-link" ) +
17
+ %(aria-current="page" aria-disabled="true">#{LABEL_TOKEN}</a></li>),
18
+ gap: %(<li class="page-item gap disabled"><a role="link" class="page-link" aria-disabled="true">#{
19
+ I18n.translate('pagy.gap')}</a></li>),
20
+ after: %(#{bootstrap_html_for(:next, a_lambda)}</ul>) }
20
21
 
21
- wrap_series_nav_js(tokens, 'pagy-bootstrap series-nav-js', **)
22
+ wrap_series_nav_js(tokens, 'pagy-bootstrap series-nav-js', **)
23
+ end
22
24
  end
23
25
  end
@@ -4,21 +4,23 @@ require_relative 'previous_next_html'
4
4
  require_relative '../support/wrap_input_nav_js'
5
5
 
6
6
  class Pagy
7
- private
7
+ module NumericHelpers
8
+ private
8
9
 
9
- # Javascript combo pagination for bulma: it returns a nav with a data-pagy attribute used by the pagy.js file
10
- def bulma_input_nav_js(classes: 'pagination', **)
11
- a_lambda = a_lambda(**)
10
+ # Javascript combo pagination for bulma: it returns a nav with a data-pagy attribute used by the pagy.js file
11
+ def bulma_input_nav_js(classes: 'pagination', **)
12
+ a_lambda = a_lambda(**)
12
13
 
13
- input = %(<input name="page" type="number" min="1" max="#{@last}" value="#{@page}" aria-current="page") +
14
- %(style="text-align: center; width: #{@page.to_s.length + 1}rem; line-height: 1.2rem; ) +
15
- %(border: none; border-radius: .25rem; padding: .0625rem; color: white; ) +
16
- %(background-color: #485fc7;">#{A_TAG})
14
+ input = %(<input name="page" type="number" min="1" max="#{@last}" value="#{@page}" aria-current="page") +
15
+ %(style="text-align: center; width: #{@page.to_s.length + 1}rem; line-height: 1.2rem; ) +
16
+ %(border: none; border-radius: .25rem; padding: .0625rem; color: white; ) +
17
+ %(background-color: #485fc7;">#{A_TAG})
17
18
 
18
- html = %(<ul class="pagination-list">#{bulma_html_for(:previous, a_lambda)}<li class="pagination-link"><label>#{
19
- I18n.translate('pagy.input_nav_js', page_input: input, pages: @last)
20
- }</label></li>#{bulma_html_for(:next, a_lambda)}</ul>)
19
+ html = %(<ul class="pagination-list">#{bulma_html_for(:previous, a_lambda)}<li class="pagination-link"><label>#{
20
+ I18n.translate('pagy.input_nav_js', page_input: input, pages: @last)
21
+ }</label></li>#{bulma_html_for(:next, a_lambda)}</ul>)
21
22
 
22
- wrap_input_nav_js(html, "pagy-bulma input-nav-js #{classes}", **)
23
+ wrap_input_nav_js(html, "pagy-bulma input-nav-js #{classes}", **)
24
+ end
23
25
  end
24
26
  end
@@ -1,19 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Pagy
4
- private
4
+ module NumericHelpers
5
+ private
5
6
 
6
- # Return the enabled/disabled previous/next page anchor tag
7
- def bulma_html_for(which, a_lambda)
8
- %(<li>#{
9
- if send(which)
10
- a_lambda.(send(which), I18n.translate("pagy.#{which}"),
11
- classes: "pagination-#{which}",
12
- aria_label: I18n.translate("pagy.aria_label.#{which}"))
13
- else
14
- %(<a role="link" class="pagination-#{which}" disabled aria-disabled="true" aria-label="#{
15
- I18n.translate("pagy.aria_label.#{which}")}">#{I18n.translate("pagy.#{which}")}</a>)
16
- end
17
- }</li>)
7
+ # Return the enabled/disabled previous/next page anchor tag
8
+ def bulma_html_for(which, a_lambda)
9
+ %(<li>#{
10
+ if send(which)
11
+ a_lambda.(send(which), I18n.translate("pagy.#{which}"),
12
+ classes: "pagination-#{which}",
13
+ aria_label: I18n.translate("pagy.aria_label.#{which}"))
14
+ else
15
+ %(<a role="link" class="pagination-#{which}" disabled aria-disabled="true" aria-label="#{
16
+ I18n.translate("pagy.aria_label.#{which}")}">#{I18n.translate("pagy.#{which}")}</a>)
17
+ end
18
+ }</li>)
19
+ end
18
20
  end
19
21
  end
@@ -4,27 +4,29 @@ require_relative 'previous_next_html'
4
4
  require_relative '../support/wrap_series_nav'
5
5
 
6
6
  class Pagy
7
- private
7
+ module NumericHelpers
8
+ private
8
9
 
9
- # Pagination for bulma: it returns the html with the series of links to the pages
10
- def bulma_series_nav(classes: 'pagination', **)
11
- a_lambda = a_lambda(**)
10
+ # Pagination for bulma: it returns the html with the series of links to the pages
11
+ def bulma_series_nav(classes: 'pagination', **)
12
+ a_lambda = a_lambda(**)
12
13
 
13
- html = %(<ul class="pagination-list">#{bulma_html_for(:previous, a_lambda)})
14
- series(**).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
15
- html << case item
16
- when Integer
17
- %(<li>#{a_lambda.(item, page_label(item), classes: 'pagination-link')}</li>)
18
- when String
19
- %(<li><a role="link" class="pagination-link is-current" aria-current="page" aria-disabled="true">#{
20
- page_label(item)}</a></li>)
21
- when :gap
22
- %(<li><span class="pagination-ellipsis">#{I18n.translate('pagy.gap')}</span></li>)
23
- else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
24
- end
25
- end
26
- html << %(#{bulma_html_for(:next, a_lambda)}</ul>)
14
+ html = %(<ul class="pagination-list">#{bulma_html_for(:previous, a_lambda)})
15
+ series(**).each do |item| # series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36]
16
+ html << case item
17
+ when Integer
18
+ %(<li>#{a_lambda.(item, page_label(item), classes: 'pagination-link')}</li>)
19
+ when String
20
+ %(<li><a role="link" class="pagination-link is-current" aria-current="page" aria-disabled="true">#{
21
+ page_label(item)}</a></li>)
22
+ when :gap
23
+ %(<li><span class="pagination-ellipsis">#{I18n.translate('pagy.gap')}</span></li>)
24
+ else raise InternalError, "expected item types in series to be Integer, String or :gap; got #{item.inspect}"
25
+ end
26
+ end
27
+ html << %(#{bulma_html_for(:next, a_lambda)}</ul>)
27
28
 
28
- wrap_series_nav(html, "pagy-bulma series-nav #{classes}", **)
29
+ wrap_series_nav(html, "pagy-bulma series-nav #{classes}", **)
30
+ end
29
31
  end
30
32
  end