pagy 43.1.1 → 43.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2d26c7bd62793daa6d3e9244fa9e01e21e13f9f2ae301b0e1a7611549f8fd69
4
- data.tar.gz: 13d1f5785fc1eb8fdf771545c2b3f83778e8ce61fa942bff1ba9140a815052f5
3
+ metadata.gz: 3856b77e08f60c0524723eb9bfa2573ff45eb3a57f6811cff02a47474dfd55f5
4
+ data.tar.gz: 6d3633c3c54bae725508c851aae01dae0082f2f94428dda03e1ecf05a6d77e1a
5
5
  SHA512:
6
- metadata.gz: b465de78aeb499d2b7949d2ba1213fc77df827b3a48e7fb55e0b019c96b143ce20d5bb013e52555f7747911bd1ee314812a4b9f57ca1ab95e42b1f9bfa298caf
7
- data.tar.gz: 689d5d5581ba78d43067f592888a19fc06d22df945158b124cea5b9eafd1a391a29969c28a798535f5f81059e92829d9a88cf52ba00f458f076e292545841370
6
+ metadata.gz: c040dfe0c8696a51ac5349442249e4a382def9be2dd73e4067cc9abecdee2ab3655c395c6c15a2e554c33fc1eea7ad2be9c9a3856d278705a8d01ba8839d56d6
7
+ data.tar.gz: 13d307256113cebbae7b25544fdd4b069194350d7e8810b405faffdccad39076d06a699deb3a1fe2a849afbc212762c1d02d377441d599fb1b9caff9c2c3bd48
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.1'
19
+ VERSION = '43.1.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.1.1'
22
+ VERSION = '43.1.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")
@@ -476,12 +476,12 @@ class MockCollection < Array
476
476
  end
477
477
 
478
478
  def offset(value)
479
- @collection = self[value..]
479
+ @collection = self[value..] || []
480
480
  self
481
481
  end
482
482
 
483
483
  def limit(value)
484
- @collection[0, value]
484
+ @collection.empty? ? [] : @collection[0, value]
485
485
  end
486
486
 
487
487
  def count(*)
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://127.0.0.1:8000
18
18
 
19
- VERSION = '43.1.1'
19
+ VERSION = '43.1.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.1.1'
19
+ VERSION = '43.1.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.1.1'
19
+ VERSION = '43.1.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.1.1'
19
+ VERSION = '43.1.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.1.1'
19
+ VERSION = '43.1.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.1.1'
19
+ VERSION = '43.1.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")
@@ -160,7 +160,7 @@ class PagyRepro < Sinatra::Base
160
160
  end
161
161
 
162
162
  # Simple array-based collection that acts as a standard DB collection.
163
- # Use it as a simple way to get a collection that acts as a AR scope, but without any DB
163
+ # Use it as a simple way to get a collection that acts as an AR scope, but without any DB
164
164
  # or create an ActiveRecord class or anything else that you need instead
165
165
  class MockCollection < Array
166
166
  def initialize(arr = Array(1..1000))
@@ -169,12 +169,12 @@ class MockCollection < Array
169
169
  end
170
170
 
171
171
  def offset(value)
172
- @collection = self[value..]
172
+ @collection = self[value..] || []
173
173
  self
174
174
  end
175
175
 
176
176
  def limit(value)
177
- @collection[0, value]
177
+ @collection.empty? ? [] : @collection[0, value]
178
178
  end
179
179
 
180
180
  def count(*)
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.1'
4
+ VERSION = '43.1.2'
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.1)
3
+ # Pagy initializer file (43.1.2)
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.1",
128
+ version: "43.1.2",
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) {
@@ -148,5 +148,5 @@ window.Pagy = (() => {
148
148
  };
149
149
  })();
150
150
 
151
- //# debugId=7800AFC87F2D38E864756E2164756E21
151
+ //# debugId=43829892A3C537E264756E2164756E21
152
152
  //# 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.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, 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.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": "7800AFC87F2D38E864756E2164756E21",
8
+ "debugId": "43829892A3C537E264756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1 +1 @@
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.1",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=(()=>{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.2",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)}}}})();
data/javascripts/pagy.mjs CHANGED
@@ -124,7 +124,7 @@ const Pagy = (() => {
124
124
  });
125
125
  };
126
126
  return {
127
- version: "43.1.1",
127
+ version: "43.1.2",
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) {
@@ -8,8 +8,8 @@ class Pagy
8
8
  assign_options(**)
9
9
  assign_and_check(limit: 1, page: 1)
10
10
  @page = upto_max_pages(@page)
11
- assign_last
12
11
  assign_offset
12
+ assign_last unless @options[:headless]
13
13
  end
14
14
 
15
15
  def records(collection)
@@ -31,9 +31,7 @@ class Pagy
31
31
  end
32
32
 
33
33
  def assign_last
34
- return unless @options[:last]
35
-
36
- @last = upto_max_pages(@options[:last].to_i)
34
+ @last = @options[:last] ? upto_max_pages(@options[:last].to_i) : @page
37
35
  end
38
36
 
39
37
  # Finalize the instance variables based on the fetched size
@@ -51,6 +49,9 @@ class Pagy
51
49
  assign_previous_and_next
52
50
  self
53
51
  end
52
+
53
+ # Support easy countless page param overriding (for legacy param and behavior)
54
+ def compose_page_param(page) = "#{page || 1}+#{@last}"
54
55
  end
55
56
  end
56
57
  end
@@ -4,7 +4,7 @@ class Pagy
4
4
  # Decouple the request from the env, allowing non-rack apps to use pagy by passing a hash.
5
5
  # Resolve the :page and :limit options from params.
6
6
  class Request
7
- def initialize(options) # default empty options for test only
7
+ def initialize(options)
8
8
  @options = options
9
9
  request = @options[:request]
10
10
  @base_url, @path, @params, @cookie =
@@ -9,7 +9,7 @@ class Pagy
9
9
  module_function
10
10
 
11
11
  # Extracted from Rack::Utils and reformatted for rubocop
12
- # Skip escaping for Pagy::RawQueryValue
12
+ # Allow unescaped Pagy::RawQueryValue
13
13
  def build_nested_query(value, prefix = nil)
14
14
  case value
15
15
  when Array
@@ -43,7 +43,7 @@ class Pagy
43
43
  params = @request.params.clone(freeze: false)
44
44
  params.delete(root_key || page_key)
45
45
  factors = {}.tap do |h|
46
- h[page_key] = countless? ? RawQueryValue.new("#{page || 1}+#{@last}") : page
46
+ h[page_key] = countless? ? RawQueryValue.new(compose_page_param(page)) : page
47
47
  h[limit_key] = limit_token || limit if client_max_limit
48
48
  end.compact # No empty params
49
49
  params.merge!(root_key ? { root_key => factors } : factors) if factors.size.positive?
@@ -15,7 +15,7 @@ class Pagy
15
15
  path = Pathname.new(__dir__)
16
16
  paginators.each { |symbol, name| autoload name, path.join(symbol.to_s) }
17
17
 
18
- # Pagy::Method defines the pagy method to be included in the app controller/view.
18
+ # Pagy::Method defines the #pagy method to be included in the app controller/view.
19
19
  Method = Module.new do
20
20
  protected
21
21
 
data/lib/pagy.rb CHANGED
@@ -10,7 +10,7 @@ require_relative 'pagy/toolbox/helpers/loader'
10
10
  class Pagy
11
11
  class RawQueryValue < String; end
12
12
 
13
- VERSION = '43.1.1'
13
+ VERSION = '43.1.2'
14
14
  ROOT = Pathname.new(__dir__).parent.freeze
15
15
  DEFAULT = { limit: 20, limit_key: 'limit', page_key: 'page' }.freeze
16
16
  PAGE_TOKEN = RawQueryValue.new('P ')
@@ -48,7 +48,7 @@ class Pagy
48
48
  def keyset? = false
49
49
  def keynav? = false
50
50
 
51
- # Validates and assign the passed options: var must be present and value.to_i must be >= to min
51
+ # Validates and assign the passed options: they must be present and value.to_i must be >= min
52
52
  def assign_and_check(name_min)
53
53
  name_min.each do |name, min|
54
54
  raise OptionError.new(self, name, ">= #{min}", @options[name]) \
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.1
4
+ version: 43.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Domizio Demichelis