pagy 43.1.8 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16e959906210363656c8985bb239027b2ed443f6fc9f1a91eb5f6415e7133825
4
- data.tar.gz: a793f4c037cde37a6a46cd2a86a2cce3f0f90ae0b65530dc09526754f81ce5bd
3
+ metadata.gz: 88bd8a007346649a403e578e204c825668c2650f8f5ec1c9a678d170546bc971
4
+ data.tar.gz: 286bbc24c67a1019e146ca9671e2ec81b8faf6f2231b433f394cdd3e72d99f85
5
5
  SHA512:
6
- metadata.gz: a32c5d0809c5973bedaf9e4b545860d4e58ede50ad9e72de178d6facdd71c5598f3dbf5289894ab919b3df9ab9704c96063d8d4e16763af6db42b22c0f90e4ab
7
- data.tar.gz: d53f557db4887a52a03eeb84e3f11ed8fa4f524264a5c22bcb93c068beb6b9da451fc2f42ab20b081069ef90f83b7c935ee7527b5eb3e19d84cfc69bb7fdd6f6
6
+ metadata.gz: 1d910c3b2b1d7105ecb68bd87df0443ccafe87450380d2e599879ba8d98c0b1b1deb94b3a4d2a431259652d5197343f0067a74c5936baf530580b1f3a4ec817e
7
+ data.tar.gz: c3fab21e05725fc9b83379b696debb7f49758c3d8dc8df017af5de2ceb59ebc3d7fc0ad7c0e90ab05779a3e0313e6ff251ce3cb3f4c2eeffc2c0092ca25792fa
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.1.8'
19
+ VERSION = '43.2.0'
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.1.8'
22
+ VERSION = '43.2.0'
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.1.8'
19
+ VERSION = '43.2.0'
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.1.8'
19
+ VERSION = '43.2.0'
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.1.8'
19
+ VERSION = '43.2.0'
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.1.8'
19
+ VERSION = '43.2.0'
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.1.8'
19
+ VERSION = '43.2.0'
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.1.8'
19
+ VERSION = '43.2.0'
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")
@@ -55,8 +55,9 @@ class PagyRepro < Sinatra::Base
55
55
  # Edit this action as needed
56
56
  get '/' do
57
57
  collection = MockCollection.new
58
- @pagy, @records = pagy(collection)
58
+ @pagy, @records = pagy(collection) # simplest form
59
59
  # @pagy, @records = pagy(:offset, collection, limit: 7, client_max_limit: 30)
60
+ # @pagy, @records = pagy(:countish, collection, ttl: 20)
60
61
  # @pagy, @records = pagy(:countless, collection)
61
62
  # @pagy, @records = pagy(Array(1..1000))
62
63
  # response.headers.merge!(@pagy.headers_hash)
data/bin/pagy CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- VERSION = '43.1.8'
4
+ VERSION = '43.2.0'
5
5
  LINUX = RbConfig::CONFIG['host_os'].include?('linux')
6
6
  HOST = 'localhost'
7
7
  PORT = '8000'
data/config/pagy.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Pagy initializer file (43.1.8)
3
+ # Pagy initializer file (43.2.0)
4
4
  # See https://ddnexus.github.io/pagy/resources/initializer/
5
5
 
6
6
  ############ Global Options ################################################################
data/javascripts/pagy.js CHANGED
@@ -125,7 +125,7 @@ window.Pagy = (() => {
125
125
  });
126
126
  };
127
127
  return {
128
- version: "43.1.8",
128
+ version: "43.2.0",
129
129
  init(arg) {
130
130
  const target = arg instanceof HTMLElement ? arg : document, elements = target.querySelectorAll("[data-pagy]");
131
131
  for (const element of elements) {
@@ -141,12 +141,13 @@ window.Pagy = (() => {
141
141
  initLimitTagJs(element, args);
142
142
  }
143
143
  } catch (err) {
144
- console.warn("Pagy.init: %o\n%s", element, err);
144
+ console.warn(`Pagy.init: %o
145
+ %s`, element, err);
145
146
  }
146
147
  }
147
148
  }
148
149
  };
149
150
  })();
150
151
 
151
- //# debugId=391D3AC59BE9808764756E2164756E21
152
+ //# debugId=E46E32F1566B8C2964756E2164756E21
152
153
  //# 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, NavJsSeries, KeynavArgs?]\ntype NavJsSeries = readonly [widths: number[],\n series: (string | number)[][],\n labels: string[][] | null]\ntype InputNavJsArgs = readonly [urlToken: string, KeynavArgs?]\ntype LimitTagJsArgs = readonly [from: number,\n urlToken: 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 pageRe = \"P \"; // shorten the compiled size\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],\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(pageRe, 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, keynavArgs]:InputNavJsArgs) => {\n const augment = keynavArgs && storageSupport\n ? await augmentKeynav(nav, keynavArgs)\n : (page: string) => page;\n initInput(nav, inputValue => url_token.replace(pageRe, augment(inputValue)));\n };\n\n // Init the limit_tag_js helper\n const initLimitTagJs = (span:HTMLSpanElement, [from, url_token]: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(pageRe, Math.max(Math.ceil(from / parseInt(inputValue)), 1))\n .replace('L ', 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 initial = input.value,\n 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 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.1.8\",\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, NavJsSeries, KeynavArgs?]\ntype NavJsSeries = readonly [widths: number[],\n series: (string | number)[][],\n labels: string[][] | null]\ntype InputNavJsArgs = readonly [urlToken: string, KeynavArgs?]\ntype LimitTagJsArgs = readonly [from: number,\n urlToken: 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 pageRe = \"P \"; // shorten the compiled size\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],\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(pageRe, 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, keynavArgs]:InputNavJsArgs) => {\n const augment = keynavArgs && storageSupport\n ? await augmentKeynav(nav, keynavArgs)\n : (page: string) => page;\n initInput(nav, inputValue => url_token.replace(pageRe, augment(inputValue)));\n };\n\n // Init the limit_tag_js helper\n const initLimitTagJs = (span:HTMLSpanElement, [from, url_token]: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(pageRe, Math.max(Math.ceil(from / parseInt(inputValue)), 1))\n .replace('L ', 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 initial = input.value,\n 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 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.2.0\",\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
- "mappings": "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",
8
- "debugId": "391D3AC59BE9808764756E2164756E21",
7
+ "mappings": ";AA2CA,IAAM,QAAQ,MAAM;AAAA,EAClB,MAAM,iBAAiB,oBAAoB,UAAU,sBAAsB,QACrE,SAAiB;AAAA,EAEvB,IAAI,OAAO,QAAQ,SAAkB,MAAwB;AAAA,EAC7D,IAAI,gBAAgB;AAAA,IAClB,UAAU;AAAA,IACV,OAAU,IAAI,iBAAiB,IAAI;AAAA,IACnC,QAAU,KAAK,IAAI;AAAA,IAEnB,KAAK,iBAAiB,WAAW,CAAC,MAA6B;AAAA,MAC7D,IAAI,EAAE,KAAK,MAAM;AAAA,QACf,MAAM,UAAU,QAAQ,QAAQ,EAAE,KAAK,GAAG;AAAA,QAC1C,IAAI,SAAS;AAAA,UACX,KAAK,YAAsB,EAAC,IAAI,EAAE,KAAK,MAAM,KAAK,EAAE,KAAK,KAAK,KAAK,QAAO,CAAC;AAAA,QAC7E;AAAA,MACF,EAAO,SAAI,EAAE,KAAK,IAAI;AAAA,QACpB,IAAI,EAAE,KAAK,MAAM,OAAO;AAAA,UACtB,QAAQ,QAAQ,EAAE,KAAK,KAAa,EAAE,KAAK,GAAG;AAAA,QAChD;AAAA,MACF;AAAA,KACD;AAAA,EACH;AAAA,EAEA,MAAM,cAAc,IAAI,eACpB,aAAW,QAAQ,QAAQ,OAAK;AAAA,IAC9B,EAAE,OAAO,iBAA+B,WAAW,EAAE,QAAQ,QAAM,GAAG,OAAO,CAAC;AAAA,GAC/E,CAAC;AAAA,EAUN,MAAM,gBAAgB,CAAC,YAAmB,KAAK,OAAO,aAAa,GAAI,IAAI,cAAa,OAAO,OAAO,CAAC,CAAC,EAC7D,QAAQ,UAAU,CAAC,MAAM,KAAK,MAAM,MAAM,KAAK,MAAM,MAAM,EAAE,GAClG,YAAgB,CAAC,WAAoB,IAAI,YAAY,EAAG,OAAO,WAAW,KAAK,KAAK,MAAM,GAAG,OAAK,EAAE,WAAW,CAAC,CAAC,CAAC;AAAA,EAGxH,MAAM,UAAU,MAAM,KAAK,MAAM,KAAK,OAAO,IAAI,MAAM,CAAC,EAAE,SAAS,EAAE;AAAA,EAGrE,MAAM,gBAA+B,OAAO,MAAM,YAAY,SAAS,SAAS,MAAM,gBAAgB;AAAA,IACpG,IAAI;AAAA,IACJ,MAAM,aAAa,SAAS,OAAO,MAAM,MAAM,EACnB,KAAK,CAAC,QAAQ,IAAI,WAAW,OAAO,GAAG,CAAC,GACvC,MAAM,GAAG,EAAE,MAAM,QAAQ;AAAA,IACtD,SAAS,SAAS,OAAO,MAAM;AAAA,IAC/B,IAAI,cAAc,EAAE,cAAc,UAAU;AAAA,MAE1C,KAAK,YAAsB,EAAE,MAAM,OAAO,KAAK,WAAW,CAAC;AAAA,MAE3D,MAAM,IAAI,QAAqB,CAAC,YAAY,WAAW,MAAM,QAAQ,EAAE,GAAG,GAAG,CAAC;AAAA,MAC9E,IAAI,EAAE,cAAc,UAAU;AAAA,QAC5B,cAAc,CAAC,SAAiB,OAAO,MAAM;AAAA,MAC/C;AAAA,IACF;AAAA,IAEA,IAAI,CAAC,aAAa;AAAA,MAChB,IAAI,CAAC,YAAY;AAAA,QAAE,GAAG;AAAA,UAAE,aAAa,QAAQ;AAAA,QAAE,SAAS,cAAc;AAAA,MAAS;AAAA,MAC/E,MAAM,OAAO,QAAQ,QAAQ,UAAU,GACnC,UAAqB,OAAO,KAAK,MAAM,IAAI,IAAI,CAAC,SAAS;AAAA,MAC7D,IAAI,YAAY;AAAA,QACd,QAAQ,OAAO,GAAG,UAAU;AAAA,QAC5B,QAAQ,QAAQ,YAAY,KAAK,UAAU,OAAO,CAAC;AAAA,MACrD;AAAA,MAEA,cAAc,CAAC,SAAgB;AAAA,QAC7B,MAAM,UAAU,SAAS,IAAI;AAAA,QAC7B,OAAO,cAAc,KAAK,UACP;AAAA,UAAC;AAAA,UACA;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR,QAAQ,UAAU;AAAA,UAClB,QAAQ;AAAA,QAAQ,CAAC,CAAC;AAAA;AAAA,IAE1C;AAAA,IACA,MAAM,SAAU,UAAW,GAAG,aAAa,eAAe;AAAA,IAC1D,MAAM,KAAS,IAAI,OAAO,iBAAiB,gBAAgB;AAAA,IAE3D,WAAW,KAA6C,IAAI,iBAAiB,SAAS,GAAG;AAAA,MACvF,EAAE,OAAO,EAAE,KAAK,QAAQ,IAAI,CAAC,QAAQ,QAAQ,UAAkB,GAAG,SAAS,YAAoB,KAAK,GAAG;AAAA,IACzG;AAAA,IAEA,OAAO;AAAA;AAAA,EAIT,MAAM,aAAa,CAAC;AAAA,KAAoB,QAAQ,QAAQ,SAAS,KAAK;AAAA,KAC/B,QAAQ,QAAQ;AAAA,IAAS;AAAA,QAAgC;AAAA,IAC9F,MAAO,SAAsB,IAAI;AAAA,IACjC,IAAI,YAAY;AAAA,KACf,IAAI,SAAS,MAAM;AAAA,MAClB,MAAM,QAAQ,OAAO,UAAU,OAAK,IAAI,OAAO,WAAW;AAAA,MAC1D,IAAI,OAAO,WAAW,WAAW;AAAA,QAAE;AAAA,MAAO;AAAA,MAE1C,IAAI,OAAO;AAAA,MACX,OAAO,OAAO,QAAQ,CAAC,MAAM,MAAM;AAAA,QAEjC,QAAQ,QAAQ,QAAQ,OAEf,OAAO,QAAQ,WAAW,OAAO,QAAQ,QAAQ,IAAI,IAAI,SACrD,QAAQ,MAAM,SAAS,OAAO,MAAM,OAAO,GAAG;AAAA,OAC5D;AAAA,MACD,QAAgB;AAAA,MAChB,IAAI,YAAY;AAAA,MAChB,IAAI,mBAAmB,cAAc,IAAI;AAAA,MACzC,YAAY,OAAO;AAAA,MACnB,IAAI,cAAc,gBAAgB;AAAA,QAAO,cAAc,KAAK,UAAU;AAAA,MAAE;AAAA,OACvE;AAAA,IACH,IAAI,IAAI,UAAU,SAAS,OAAO,MAAM,GAAG;AAAA,MAAE,YAAY,QAAQ,MAAM;AAAA,IAAE;AAAA;AAAA,EAI3E,MAAM,iBAAiB,OAAO,MAAkB,WAAW,gBAA+B;AAAA,IACxF,MAAM,UAAU,cAAc,iBACZ,MAAM,cAAc,KAAK,UAAU,IACnC,CAAC,SAAiB;AAAA,IACpC,UAAU,KAAK,gBAAc,UAAU,QAAQ,QAAQ,QAAQ,UAAU,CAAC,CAAC;AAAA;AAAA,EAI7E,MAAM,iBAAiB,CAAC,OAAuB,MAAM,eAA8B;AAAA,IACjF,UAAU,MAAM,gBAAc;AAAA,MAE5B,OAAO,UAAU,QAAQ,QAAQ,KAAK,IAAI,KAAK,KAAK,OAAO,SAAS,UAAU,CAAC,GAAG,CAAC,CAAC,EACnE,QAAQ,MAAM,UAAU;AAAA,KAC1C;AAAA;AAAA,EAIH,MAAM,YAAY,CAAC,SAAqB,WAAgC;AAAA,IACtE,MAAM,QAA4B,QAAQ,cAAc,OAAO,GACzD,OAA6B,QAAQ,cAAc,GAAG,GACtD,UAAU,MAAM,OAChB,SAAU,MAAM;AAAA,MACJ,IAAI,MAAM,UAAU,SAAS;AAAA,QAAE;AAAA,MAAO;AAAA,MACtC,OAAO,KAAK,KAAK,OAAO,CAAC,MAAM,KAAK,MAAM,OAAO,MAAM,GAAG,EAAE,IAAI,OAAK,SAAS,CAAC,KAAK,CAAC;AAAA,MACrF,IAAI,MAAM,OAAO,MAAM,KAAK;AAAA,QAC1B,MAAM,QAAQ;AAAA,QACd,MAAM,OAAO;AAAA,QACb;AAAA,MACF;AAAA,MACA,KAAK,OAAO,OAAO,MAAM,KAAK;AAAA,MAC9B,KAAK,MAAM;AAAA;AAAA,IAE7B,MAAM,iBAAiB,SAAS,MAAM,MAAM,OAAO,CAAC;AAAA,IACpD,MAAM,iBAAiB,YAAY,MAAM;AAAA,IACzC,MAAM,iBAAiB,YAAY,OAAK;AAAA,MAAE,IAAI,EAAE,OAAO,SAAS;AAAA,QAAE,OAAO;AAAA,MAAE;AAAA,KAAG;AAAA;AAAA,EAIhF,OAAO;AAAA,IACL,SAAS;AAAA,IAGT,IAAI,CAAC,KAAkB;AAAA,MACrB,MAAM,SAAW,eAAe,cAAc,MAAM,UAC9C,WAAW,OAAO,iBAAiB,aAAa;AAAA,MACtD,WAAW,WAAoC,UAAU;AAAA,QACvD,IAAI;AAAA,UACF,OAAO,aAAa,QAAkB,KAAK,MAAM,UAAkB,QAAQ,aAAa,WAAW,CAAC,CAAC;AAAA,UACrG,IAAI,YAAY,KAAK;AAAA,YAEd,cAAc,SAAS,GAAwB,IAAI;AAAA,UAC1D,EAAO,SAAI,YAAY,OAAO;AAAA,YAC5B,WAAyB,SAAmC,IAAI;AAAA,UAClE,EAAO,SAAI,YAAY,OAAO;AAAA,YACvB,eAAe,SAAkC,IAAI;AAAA,UAC5D,EAAO,SAAI,YAAY,OAAO;AAAA,YAC5B,eAAe,SAAkC,IAAI;AAAA,UACvD;AAAA,UAEA,OAAO,KAAK;AAAA,UAAE,QAAQ,KAAK;AAAA,KAAqB,SAAS,GAAG;AAAA;AAAA,MAChE;AAAA;AAAA,EAEJ;AAAA,GACC;",
8
+ "debugId": "E46E32F1566B8C2964756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1 +1,2 @@
1
- window.Pagy=(()=>{const T="sessionStorage"in window&&"BroadcastChannel"in window;let L="pagy",Y,O,B;if(T)Y=sessionStorage,O=new BroadcastChannel(L),B=Date.now(),O.addEventListener("message",(q)=>{if(q.data.from){const z=Y.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==B)Y.setItem(q.data.key,q.data.str)}});const S=new ResizeObserver((q)=>q.forEach((z)=>{z.target.querySelectorAll(".pagy-rjs").forEach((C)=>C.render())})),_=(q)=>btoa(String.fromCharCode(...new TextEncoder().encode(q))).replace(/[+/=]/g,(z)=>z=="+"?"-":z=="/"?"_":""),N=(q)=>new TextDecoder().decode(Uint8Array.from(atob(q),(z)=>z.charCodeAt(0))),J=()=>Math.floor(Math.random()*46656).toString(36),W=async(q,[z,C,F,G,Q])=>{let M;const $=document.cookie.split(/;\s+/).find((H)=>H.startsWith(L+"="))?.split("=")[1]??J();if(document.cookie=L+"="+$,z&&!(z in Y)){if(O.postMessage({from:B,key:z}),await new Promise((H)=>setTimeout(()=>H(""),100)),!(z in Y))M=(H)=>H+"+"+G}if(!M){if(!z)do z=J();while(z in Y);const H=Y.getItem(z),R=H?JSON.parse(H):[void 0];if(Q)R.splice(...Q),Y.setItem(z,JSON.stringify(R));M=(Z)=>{const X=parseInt(Z);return _(JSON.stringify([$,z,X,R.length,R[X-1],R[X]]))}}const E=C?`${C}%5B${F}%5D`:F,j=new RegExp(`(?<=\\?.*)(\\b${E}=)(\\d+)`);for(let H of q.querySelectorAll("a[href]"))H.href=H.href.replace(j,(R,Z,X)=>`${Z}${M(X)}`);return M},P=(q,[[z,C,F,G,Q],[M,$,E],j])=>{const H=q.parentElement;let R=-1;if((q.render=()=>{const Z=M.findIndex((D)=>D<H.clientWidth);if(M[Z]===R)return;let X=z;if($[Z].forEach((D,A)=>{X+=D=="gap"?G:(typeof D=="number"?C.replace("P ",D):F).replace("L<",E?.[Z][A]??D+"<")}),X+=Q,q.innerHTML="",q.insertAdjacentHTML("afterbegin",X),R=M[Z],j&&T)W(q,j)})(),q.classList.contains(L+"-rjs"))S.observe(H)},V=async(q,[z,C])=>{const F=C&&T?await W(q,C):(G)=>G;U(q,(G)=>z.replace("P ",F(G)))},x=(q,[z,C])=>{U(q,(F)=>{return C.replace("P ",Math.max(Math.ceil(z/parseInt(F)),1)).replace("L ",F)})},U=(q,z)=>{const C=q.querySelector("input"),F=q.querySelector("a"),G=C.value,Q=()=>{if(C.value===G)return;const[M,$,E]=[C.min,C.value,C.max].map((j)=>parseInt(j)||0);if($<M||$>E){C.value=G,C.select();return}F.href=z(C.value),F.click()};C.addEventListener("focus",()=>C.select()),C.addEventListener("focusout",Q),C.addEventListener("keypress",(M)=>{if(M.key=="Enter")Q()})};return{version:"43.1.8",init(q){const z=q instanceof HTMLElement?q:document,C=z.querySelectorAll("[data-pagy]");for(let F of C)try{const[G,...Q]=JSON.parse(N(F.getAttribute("data-pagy")));if(G=="k")W(F,...Q);else if(G=="snj")P(F,Q);else if(G=="inj")V(F,Q);else if(G=="ltj")x(F,Q)}catch(G){console.warn("Pagy.init: %o\n%s",F,G)}}}})();
1
+ window.Pagy=(()=>{let T="sessionStorage"in window&&"BroadcastChannel"in window,L="pagy",Y,O,B;if(T)Y=sessionStorage,O=new BroadcastChannel(L),B=Date.now(),O.addEventListener("message",(q)=>{if(q.data.from){let z=Y.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==B)Y.setItem(q.data.key,q.data.str)}});let S=new ResizeObserver((q)=>q.forEach((z)=>{z.target.querySelectorAll(".pagy-rjs").forEach((C)=>C.render())})),_=(q)=>btoa(String.fromCharCode(...new TextEncoder().encode(q))).replace(/[+/=]/g,(z)=>z=="+"?"-":z=="/"?"_":""),N=(q)=>new TextDecoder().decode(Uint8Array.from(atob(q),(z)=>z.charCodeAt(0))),J=()=>Math.floor(Math.random()*46656).toString(36),W=async(q,[z,C,F,G,Q])=>{let M,$=document.cookie.split(/;\s+/).find((H)=>H.startsWith(L+"="))?.split("=")[1]??J();if(document.cookie=L+"="+$,z&&!(z in Y)){if(O.postMessage({from:B,key:z}),await new Promise((H)=>setTimeout(()=>H(""),100)),!(z in Y))M=(H)=>H+"+"+G}if(!M){if(!z)do z=J();while(z in Y);let H=Y.getItem(z),R=H?JSON.parse(H):[void 0];if(Q)R.splice(...Q),Y.setItem(z,JSON.stringify(R));M=(Z)=>{let X=parseInt(Z);return _(JSON.stringify([$,z,X,R.length,R[X-1],R[X]]))}}let E=C?`${C}%5B${F}%5D`:F,j=new RegExp(`(?<=\\?.*)(\\b${E}=)(\\d+)`);for(let H of q.querySelectorAll("a[href]"))H.href=H.href.replace(j,(R,Z,X)=>`${Z}${M(X)}`);return M},P=(q,[[z,C,F,G,Q],[M,$,E],j])=>{let H=q.parentElement,R=-1;if((q.render=()=>{let Z=M.findIndex((D)=>D<H.clientWidth);if(M[Z]===R)return;let X=z;if($[Z].forEach((D,A)=>{X+=D=="gap"?G:(typeof D=="number"?C.replace("P ",D):F).replace("L<",E?.[Z][A]??D+"<")}),X+=Q,q.innerHTML="",q.insertAdjacentHTML("afterbegin",X),R=M[Z],j&&T)W(q,j)})(),q.classList.contains(L+"-rjs"))S.observe(H)},V=async(q,[z,C])=>{let F=C&&T?await W(q,C):(G)=>G;U(q,(G)=>z.replace("P ",F(G)))},x=(q,[z,C])=>{U(q,(F)=>{return C.replace("P ",Math.max(Math.ceil(z/parseInt(F)),1)).replace("L ",F)})},U=(q,z)=>{let C=q.querySelector("input"),F=q.querySelector("a"),G=C.value,Q=()=>{if(C.value===G)return;let[M,$,E]=[C.min,C.value,C.max].map((j)=>parseInt(j)||0);if($<M||$>E){C.value=G,C.select();return}F.href=z(C.value),F.click()};C.addEventListener("focus",()=>C.select()),C.addEventListener("focusout",Q),C.addEventListener("keypress",(M)=>{if(M.key=="Enter")Q()})};return{version:"43.2.0",init(q){let z=q instanceof HTMLElement?q:document,C=z.querySelectorAll("[data-pagy]");for(let F of C)try{let[G,...Q]=JSON.parse(N(F.getAttribute("data-pagy")));if(G=="k")W(F,...Q);else if(G=="snj")P(F,Q);else if(G=="inj")V(F,Q);else if(G=="ltj")x(F,Q)}catch(G){console.warn(`Pagy.init: %o
2
+ %s`,F,G)}}}})();
data/javascripts/pagy.mjs CHANGED
@@ -124,7 +124,7 @@ const Pagy = (() => {
124
124
  });
125
125
  };
126
126
  return {
127
- version: "43.1.8",
127
+ version: "43.2.0",
128
128
  init(arg) {
129
129
  const target = arg instanceof HTMLElement ? arg : document, elements = target.querySelectorAll("[data-pagy]");
130
130
  for (const element of elements) {
@@ -140,7 +140,8 @@ const Pagy = (() => {
140
140
  initLimitTagJs(element, args);
141
141
  }
142
142
  } catch (err) {
143
- console.warn("Pagy.init: %o\n%s", element, err);
143
+ console.warn(`Pagy.init: %o
144
+ %s`, element, err);
144
145
  }
145
146
  }
146
147
  }
data/javascripts/wand.js CHANGED
@@ -62,7 +62,7 @@ const fontIsolation = (async () => {
62
62
  let cssText = await response.text();
63
63
  fontMappings.forEach((mapping) => {
64
64
  const regex = new RegExp(`(font-family:\\s*['"]?)${mapping.original}(['"]?;?)`, "g");
65
- cssText = cssText.replace(regex, `\$1${mapping.custom}\$2`);
65
+ cssText = cssText.replace(regex, `$1${mapping.custom}$2`);
66
66
  });
67
67
  classMappings.forEach((mapping) => {
68
68
  const regex = new RegExp(`\\.(${mapping.original})(?=[\\s\\.{,:])`, "g");
@@ -70,7 +70,9 @@ const fontIsolation = (async () => {
70
70
  });
71
71
  const fontFaceRegex = /(?:\/\*[\s\S]*?\*\/[\s\n]*)?@font-face\s*\{[^}]*}/g;
72
72
  const fontFaceMatches = cssText.match(fontFaceRegex);
73
- result.fontFaceRules = fontFaceMatches ? fontFaceMatches.join("\n\n") : "";
73
+ result.fontFaceRules = fontFaceMatches ? fontFaceMatches.join(`
74
+
75
+ `) : "";
74
76
  result.componentCss = cssText.replace(fontFaceRegex, "").trim();
75
77
  } catch (error) {
76
78
  console.error("Failed to process Google Font CSS:", fontCssUrl, error);
@@ -79,8 +81,10 @@ const fontIsolation = (async () => {
79
81
  return result;
80
82
  }
81
83
  const processedResults = await Promise.all(fontDefinitions.map((def) => processGoogleFontCSS(def.url, def.fontMappings, def.classMappings)));
82
- const allFontFaceRules = processedResults.map((r) => r.fontFaceRules).join("\n");
83
- const allComponentCss = processedResults.map((r) => r.componentCss).join("\n");
84
+ const allFontFaceRules = processedResults.map((r) => r.fontFaceRules).join(`
85
+ `);
86
+ const allComponentCss = processedResults.map((r) => r.componentCss).join(`
87
+ `);
84
88
  if (allFontFaceRules) {
85
89
  const styleEl = document.createElement("style");
86
90
  styleEl.id = "pagy-wand-font-css";
@@ -696,11 +700,11 @@ document.addEventListener("DOMContentLoaded", async () => {
696
700
  </dd>
697
701
  </dl>
698
702
  <h4>Customizing</h4>
699
- <p>\u2022 You can change Pagy's styling quite radically, by just setting a few CSS Custom Properties:
703
+ <p>• You can change Pagy's styling quite radically, by just setting a few CSS Custom Properties:
700
704
  the <code><i>pagy.css</i></code> or <code><i>pagy-tailwind.css</i></code> calculates all the other metrics.</p>
701
- <p>\u2022 Pick a Presets as a starting point, customize it with the controls,
705
+ <p>• Pick a Presets as a starting point, customize it with the controls,
702
706
  and copy/paste the CSS Override in your Stylesheet.</p>
703
- <p>\u2022 Add further customization to the <code>.pagy</code> CSS Override, or override the calculated properties
707
+ <p>• Add further customization to the <code>.pagy</code> CSS Override, or override the calculated properties
704
708
  for full control over the final style.</p>
705
709
  <p><b>Important</b>: Do not link the Pagy CSS file. Copy its customized content in your CSS,
706
710
  to avoid unwanted cosmetic changes that could happen on update.</p>
@@ -973,10 +977,12 @@ document.addEventListener("DOMContentLoaded", async () => {
973
977
  applyCSS(presetCSS);
974
978
  }
975
979
  function updateOverride() {
976
- let override = `.pagy {\n`;
980
+ let override = `.pagy {
981
+ `;
977
982
  Object.values(controls).forEach((c) => {
978
983
  if (c.name !== "") {
979
- override += ` ${c.name}: ${c.input.value}${c.unit};\n`;
984
+ override += ` ${c.name}: ${c.input.value}${c.unit};
985
+ `;
980
986
  }
981
987
  });
982
988
  override += "}";
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Pagy
4
+ class Offset
5
+ # Offset pagination with memoized count
6
+ class Countish < Offset
7
+ protected
8
+
9
+ # Return page+count or page+count+epoch
10
+ def compose_page_param(page)
11
+ value = "#{page || 1}+#{@count}"
12
+ value << "+#{@options[:epoch]}" if @options[:epoch]
13
+ EscapedValue.new(value)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -55,7 +55,7 @@ class Pagy
55
55
  end
56
56
 
57
57
  # Support easy countless page param overriding (for legacy param and behavior)
58
- def compose_page_param(page) = "#{page || 1}+#{@last}"
58
+ def compose_page_param(page) = EscapedValue.new("#{page || 1}+#{@last}")
59
59
  end
60
60
  end
61
61
  end
@@ -9,6 +9,7 @@ class Pagy
9
9
  DEFAULT = { page: 1 }.freeze
10
10
 
11
11
  autoload :Countless, Pathname.new(__dir__).join('countless')
12
+ autoload :Countish, Pathname.new(__dir__).join('countish')
12
13
 
13
14
  include Rangeable
14
15
  include Shiftable
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Pagy
4
+ # Provide the helpers to count a collection
5
+ module Countable
6
+ module_function
7
+
8
+ # Get the collection count
9
+ def get_count(collection, options)
10
+ return collection.size if collection.instance_of?(Array)
11
+ return collection.count unless defined?(::ActiveRecord) && collection.is_a?(::ActiveRecord::Relation)
12
+
13
+ count = if options[:count_over] && !collection.group_values.empty?
14
+ # COUNT(*) OVER ()
15
+ sql = Arel.star.count.over(Arel::Nodes::Grouping.new([]))
16
+ collection.unscope(:order).pick(sql).to_i
17
+ else
18
+ collection.count(:all)
19
+ end
20
+ count.is_a?(Hash) ? count.size : count
21
+ end
22
+ end
23
+ end
@@ -3,6 +3,9 @@
3
3
  require 'uri'
4
4
 
5
5
  class Pagy
6
+ # Support spaces in placeholder params
7
+ class EscapedValue < String; end
8
+
6
9
  # Provide the helpers to handle the url and anchor
7
10
  module Linkable
8
11
  module QueryUtils
@@ -23,8 +26,8 @@ class Pagy
23
26
  else
24
27
  raise ArgumentError, 'value must be a Hash' if prefix.nil?
25
28
 
26
- final_value = value.is_a?(RawQueryValue) ? value.to_s : escape(value)
27
- "#{escape(prefix)}=#{final_value}"
29
+ escaped_value = value.is_a?(EscapedValue) ? value : escape(value)
30
+ "#{escape(prefix)}=#{escaped_value}"
28
31
  end
29
32
  end
30
33
 
@@ -35,15 +38,18 @@ class Pagy
35
38
 
36
39
  protected
37
40
 
41
+ # Overriddable by classes with composite page param
42
+ def compose_page_param(page) = page
43
+
38
44
  # Return the URL for the page, relying on the Pagy::Request
39
- def compose_page_url(page, limit_token: nil, **options)
40
- root_key, page_key, limit_key, limit, client_max_limit, querify, absolute, path, fragment =
45
+ def compose_page_url(page, **options)
46
+ root_key, page_key, limit_key, client_max_limit, limit, querify, absolute, path, fragment =
41
47
  @options.merge(options)
42
- .values_at(:root_key, :page_key, :limit_key, :limit, :client_max_limit, :querify, :absolute, :path, :fragment)
48
+ .values_at(:root_key, :page_key, :limit_key, :client_max_limit, :limit, :querify, :absolute, :path, :fragment)
43
49
  params = @request.params.clone(freeze: false)
44
50
  (root_key ? params[root_key] ||= {} : params).tap do |h|
45
- { page_key => countless? ? RawQueryValue.new(compose_page_param(page)) : page,
46
- limit_key => (limit_token || limit if client_max_limit) }.each { |k, v| v ? h[k] = v : h.delete(k) }
51
+ { page_key => compose_page_param(page),
52
+ limit_key => client_max_limit && limit }.each { |k, v| v ? h[k] = v : h.delete(k) }
47
53
  end
48
54
  querify&.(params) # Must modify the params: the returned value is ignored
49
55
  query_string = QueryUtils.build_nested_query(params).sub(/\A(?=.)/, '?')
@@ -7,9 +7,9 @@ class Pagy
7
7
  def limit_tag_js(id: nil, item_name: nil, client_max_limit: @options[:client_max_limit], **)
8
8
  raise OptionError.new(self, :client_max_limit, 'to be truthy', client_max_limit) unless client_max_limit
9
9
 
10
- url_token = compose_page_url(PAGE_TOKEN, limit_token: LIMIT_TOKEN)
11
10
  limit_input = %(<input name="limit" type="number" min="1" max="#{@options[:client_max_limit]}" value="#{
12
11
  @limit}" style="padding: 0; text-align: center; width: #{@limit.to_s.length + 1}rem;">#{A_TAG})
12
+ url_token = compose_page_url(PAGE_TOKEN, limit: LIMIT_TOKEN)
13
13
 
14
14
  %(<span#{%( id="#{id}") if id} class="pagy limit-tag-js" #{
15
15
  data_pagy_attribute(:ltj, @from, url_token)
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../modules/abilities/countable'
4
+
5
+ class Pagy
6
+ module CountishPaginator
7
+ module_function
8
+
9
+ # Return the Offset::Countish instance and records
10
+ def paginate(collection, options)
11
+ options[:page] ||= options[:request].resolve_page(force_integer: false)
12
+ if options[:page].is_a?(String)
13
+ page, count, epoch = options[:page].split.map(&:to_i)
14
+ options[:page] = page
15
+ end
16
+ setup_options(count, epoch, collection, options)
17
+ options[:limit] = options[:request].resolve_limit
18
+ pagy = Offset::Countish.new(**options)
19
+ [pagy, pagy.records(collection)]
20
+ end
21
+
22
+ # Get the count from the page and set epoch when ttl (Time To Live) requires it
23
+ def setup_options(count, epoch, collection, options)
24
+ now = Time.now.to_i
25
+ if !options[:count] && count && (!options[:ttl] ||
26
+ (epoch && epoch <= now && now < (epoch + options[:ttl]))) # ongoing
27
+ # puts 'ongoing'
28
+ options[:count] = count
29
+ options[:epoch] = epoch if options[:ttl]
30
+ else # recount
31
+ # puts 'recount'
32
+ options[:count] ||= Countable.get_count(collection, options)
33
+ options[:epoch] = now if options[:ttl]
34
+ end
35
+ end
36
+ end
37
+ end
@@ -8,7 +8,7 @@ class Pagy
8
8
  def paginate(collection, options)
9
9
  options[:page] ||= options[:request].resolve_page(force_integer: false) # accept nil and strings
10
10
  if options[:page].is_a?(String)
11
- page, last = options[:page].split(/ /, 2).map(&:to_i) # decoded '+' added by the compose_page_url
11
+ page, last = options[:page].split.map(&:to_i) # decoded '+' added by the compose_page_url
12
12
  options[:page] = page
13
13
  options[:last] = last if last&.positive?
14
14
  end
@@ -5,6 +5,7 @@ require_relative '../../classes/request'
5
5
  class Pagy
6
6
  paginators = { offset: :OffsetPaginator,
7
7
  countless: :CountlessPaginator,
8
+ countish: :CountishPaginator,
8
9
  keyset: :KeysetPaginator,
9
10
  keynav_js: :KeynavJsPaginator,
10
11
  calendar: :CalendarPaginator,
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../../modules/abilities/countable'
4
+
3
5
  class Pagy
4
6
  module OffsetPaginator
5
7
  module_function
@@ -8,23 +10,9 @@ class Pagy
8
10
  def paginate(collection, options)
9
11
  options[:page] ||= options[:request].resolve_page
10
12
  options[:limit] = options[:request].resolve_limit
11
- options[:count] ||= collection.instance_of?(Array) ? collection.size : OffsetPaginator.get_count(collection, options)
13
+ options[:count] ||= Countable.get_count(collection, options)
12
14
  pagy = Offset.new(**options)
13
15
  [pagy, collection.instance_of?(Array) ? collection[pagy.offset, pagy.limit] : pagy.records(collection)]
14
16
  end
15
-
16
- # Get the collection count
17
- def get_count(collection, options)
18
- return collection.count unless defined?(::ActiveRecord) && collection.is_a?(::ActiveRecord::Relation)
19
-
20
- count = if options[:count_over] && !collection.group_values.empty?
21
- # COUNT(*) OVER ()
22
- sql = Arel.star.count.over(Arel::Nodes::Grouping.new([]))
23
- collection.unscope(:order).pick(sql).to_i
24
- else
25
- collection.count(:all)
26
- end
27
- count.is_a?(Hash) ? count.size : count
28
- end
29
17
  end
30
18
  end
data/lib/pagy.rb CHANGED
@@ -8,13 +8,11 @@ require_relative 'pagy/toolbox/helpers/loader'
8
8
 
9
9
  # Top superclass: it defines only what's common to all the subclasses
10
10
  class Pagy
11
- class RawQueryValue < String; end
12
-
13
- VERSION = '43.1.8'
11
+ VERSION = '43.2.0'
14
12
  ROOT = Pathname.new(__dir__).parent.freeze
15
13
  DEFAULT = { limit: 20, limit_key: 'limit', page_key: 'page' }.freeze
16
- PAGE_TOKEN = RawQueryValue.new('P ')
17
- LIMIT_TOKEN = RawQueryValue.new('L ')
14
+ PAGE_TOKEN = EscapedValue.new('P ')
15
+ LIMIT_TOKEN = EscapedValue.new('L ')
18
16
  LABEL_TOKEN = 'L'
19
17
  A_TAG = '<a style="display: none;">#</a>'
20
18
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pagy
3
3
  version: !ruby/object:Gem::Version
4
- version: 43.1.8
4
+ version: 43.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Domizio Demichelis
@@ -82,12 +82,14 @@ files:
82
82
  - lib/pagy/classes/keyset/keynav/sequel.rb
83
83
  - lib/pagy/classes/keyset/keyset.rb
84
84
  - lib/pagy/classes/keyset/sequel.rb
85
+ - lib/pagy/classes/offset/countish.rb
85
86
  - lib/pagy/classes/offset/countless.rb
86
87
  - lib/pagy/classes/offset/offset.rb
87
88
  - lib/pagy/classes/offset/search.rb
88
89
  - lib/pagy/classes/request.rb
89
90
  - lib/pagy/console.rb
90
91
  - lib/pagy/modules/abilities/configurable.rb
92
+ - lib/pagy/modules/abilities/countable.rb
91
93
  - lib/pagy/modules/abilities/linkable.rb
92
94
  - lib/pagy/modules/abilities/rangeable.rb
93
95
  - lib/pagy/modules/abilities/shiftable.rb
@@ -130,6 +132,7 @@ files:
130
132
  - lib/pagy/toolbox/helpers/support/wrap_series_nav_js.rb
131
133
  - lib/pagy/toolbox/helpers/urls_hash.rb
132
134
  - lib/pagy/toolbox/paginators/calendar.rb
135
+ - lib/pagy/toolbox/paginators/countish.rb
133
136
  - lib/pagy/toolbox/paginators/countless.rb
134
137
  - lib/pagy/toolbox/paginators/elasticsearch_rails.rb
135
138
  - lib/pagy/toolbox/paginators/keynav_js.rb
@@ -202,7 +205,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
202
205
  - !ruby/object:Gem::Version
203
206
  version: '0'
204
207
  requirements: []
205
- rubygems_version: 3.6.7
208
+ rubygems_version: 3.6.9
206
209
  specification_version: 4
207
210
  summary: "Pagy \U0001F438 The Leaping Gem!"
208
211
  test_files: []