pagy 9.3.4 → 9.4.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: 9d2835c37aa941ceeee1a7ab05ca98e78e6f259a5ad96582dcf06a5fc7f9ed1b
4
- data.tar.gz: 2697b8be5d353ffadca19d4c02d132fba5f355b89183c3f8fb0584ed4ea71c78
3
+ metadata.gz: 299a8b4a13505d582a4a53f55a2680f6a9eb753e2a70bde82e40123f0b9513b5
4
+ data.tar.gz: e087528050227a308bec04266f88cb299ed1dfc16c1b9687898f7878aedd1217
5
5
  SHA512:
6
- metadata.gz: 6f6b9e70680ddb584a52b9bb6f8fcdabc3b9715fce006ea3be3a2a708817f7ccb87ad5b70749deb1c4682fc89413609ad359a896a889fc88506ae94669710d14
7
- data.tar.gz: 00c132f27373a3b0e517aa1bd42976c6276d6144540b4be153251302a83b572737a65172beb41dfc10b1a1876af99d18812577326c0b3c50a6c51c317ecf0233
6
+ metadata.gz: ee1a34abed31375c6476e08a77900e6d73f4c8e4e86f9669b917a949b6f7f0b78ebcf616c51e2d9b94daf89c39a81dbf08652bc804c0272c7426fc57c939a395
7
+ data.tar.gz: 0bdc3672694d8b184e1ef8b1b5f14729bfc7f387462a5f85336261c3e1568f785583964220d200542c1a98ad7ca81687e8ab7ae9ddd5e41a7877e3818c2fc549
data/apps/calendar.ru CHANGED
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://0.0.0.0:8000
18
18
 
19
- VERSION = '9.3.4'
19
+ VERSION = '9.4.0'
20
20
 
21
21
  # Bundle
22
22
  require 'bundler/inline'
data/apps/demo.ru CHANGED
@@ -19,7 +19,7 @@
19
19
  # URL
20
20
  # http://0.0.0.0:8000
21
21
 
22
- VERSION = '9.3.4'
22
+ VERSION = '9.4.0'
23
23
 
24
24
  # Bundle
25
25
  require 'bundler/inline'
data/apps/keyset_ar.ru CHANGED
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://0.0.0.0:8000
18
18
 
19
- VERSION = '9.3.4'
19
+ VERSION = '9.4.0'
20
20
 
21
21
  # Bundle
22
22
  require 'bundler/inline'
@@ -42,6 +42,7 @@ require 'sinatra/base'
42
42
  # Sinatra application
43
43
  class PagyKeyset < Sinatra::Base
44
44
  include Pagy::Backend
45
+
45
46
  # Root route/action
46
47
  get '/' do
47
48
  Time.zone = 'UTC'
data/apps/keyset_s.ru CHANGED
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://0.0.0.0:8000
18
18
 
19
- VERSION = '9.3.4'
19
+ VERSION = '9.4.0'
20
20
 
21
21
  # Bundle
22
22
  require 'bundler/inline'
@@ -43,6 +43,7 @@ require 'logger'
43
43
  # Sinatra application
44
44
  class PagyKeyset < Sinatra::Base
45
45
  include Pagy::Backend
46
+
46
47
  # Root route/action
47
48
  get '/' do
48
49
  @order = { animal: :asc, name: :asc, birthdate: :desc, id: :asc }
data/apps/rails.ru CHANGED
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://0.0.0.0:8000
18
18
 
19
- VERSION = '9.3.4'
19
+ VERSION = '9.4.0'
20
20
 
21
21
  # Gemfile
22
22
  require 'bundler/inline'
data/apps/repro.ru CHANGED
@@ -16,7 +16,7 @@
16
16
  # URL
17
17
  # http://0.0.0.0:8000
18
18
 
19
- VERSION = '9.3.4'
19
+ VERSION = '9.4.0'
20
20
 
21
21
  # Bundle
22
22
  require 'bundler/inline'
data/bin/pagy CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- VERSION = '9.3.4'
4
+ VERSION = '9.4.0'
5
5
  LINUX = RbConfig::CONFIG['host_os'].include?('linux')
6
6
  HOST = '0.0.0.0'
7
7
  PORT = '8000'
@@ -58,14 +58,14 @@ end
58
58
  arg = ARGV.shift
59
59
  if arg.eql?('clone')
60
60
  name = ARGV.shift
61
- Optimist.die("Expected APP to be in [#{apps.keys.join(', ')}]; got #{arg.inspect}") unless apps.key?(arg)
61
+ Optimist.die("Expected APP to be in [#{apps.keys.join(', ')}]; got #{name.inspect}") unless apps.key?(name)
62
62
  if File.exist?(name)
63
63
  print "Do you want to overwrite the #{name.inspect} file? (y/n)> "
64
64
  answer = gets.chomp
65
65
  Optimist.die("#{name.inspect} file already present") unless answer.start_with?(/y/i)
66
66
  end
67
67
  require 'fileutils'
68
- FileUtils.cp(apps[arg], '.', verbose: true)
68
+ FileUtils.cp(apps[name], '.', verbose: true)
69
69
  else
70
70
  if apps.key?(arg) # showcase env
71
71
  opts[:env] = 'showcase'
data/config/pagy.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Pagy initializer file (9.3.4)
3
+ # Pagy initializer file (9.4.0)
4
4
  # Customize only what you really need and notice that the core Pagy works also without any of the following lines.
5
5
  # Should you just cherry pick part of this file, please maintain the require-order of the extras
6
6
 
@@ -1,4 +1,4 @@
1
- window.Pagy=(()=>{const j=new ResizeObserver((B)=>B.forEach((D)=>D.target.querySelectorAll(".pagy-rjs").forEach((E)=>E.pagyRender()))),x=(B,[D,E,z,G])=>{const F=B.parentElement??B,K=Object.keys(E).map((H)=>parseInt(H)).sort((H,M)=>M-H);let L=-1;const T=(H,M,R)=>H.replace(/__pagy_page__/g,M).replace(/__pagy_label__/g,R);if((B.pagyRender=function(){const H=K.find((Q)=>Q<F.clientWidth)||0;if(H===L)return;let M=D.before;const R=E[H.toString()],X=z?.[H.toString()]??R.map((Q)=>Q.toString());R.forEach((Q,J)=>{const $=X[J];let U;if(typeof Q==="number")U=T(D.a,Q.toString(),$);else if(Q==="gap")U=D.gap;else U=T(D.current,Q,$);M+=typeof G==="string"&&Q==1?Z(U,G):U}),M+=D.after,B.innerHTML="",B.insertAdjacentHTML("afterbegin",M),L=H})(),B.classList.contains("pagy-rjs"))j.observe(F)},A=(B,[D,E])=>Y(B,(z)=>[z,D.replace(/__pagy_page__/,z)],E),C=(B,[D,E,z])=>{Y(B,(G)=>{const F=Math.max(Math.ceil(D/parseInt(G)),1).toString(),K=E.replace(/__pagy_page__/,F).replace(/__pagy_limit__/,G);return[F,K]},z)},Y=(B,D,E)=>{const z=B.querySelector("input"),G=B.querySelector("a"),F=z.value,K=function(){if(z.value===F)return;const[L,T,H]=[z.min,z.value,z.max].map((X)=>parseInt(X)||0);if(T<L||T>H){z.value=F,z.select();return}let[M,R]=D(z.value);if(typeof E==="string"&&M==="1")R=Z(R,E);G.href=R,G.click()};["change","focus"].forEach((L)=>z.addEventListener(L,()=>z.select())),z.addEventListener("focusout",K),z.addEventListener("keypress",(L)=>{if(L.key==="Enter")K()})},Z=(B,D)=>B.replace(new RegExp(`[?&]${D}=1\\b(?!&)|\\b${D}=1&`),"");return{version:"9.3.4",init(B){const E=(B instanceof Element?B:document).querySelectorAll("[data-pagy]");for(let z of E)try{const G=Uint8Array.from(atob(z.getAttribute("data-pagy")),(L)=>L.charCodeAt(0)),[F,...K]=JSON.parse(new TextDecoder().decode(G));if(F==="nav")x(z,K);else if(F==="combo")A(z,K);else if(F==="selector")C(z,K);else console.warn("Skipped Pagy.init() for: %o\nUnknown keyword '%s'",z,F)}catch(G){console.warn("Skipped Pagy.init() for: %o\n%s",z,G)}}}})();
1
+ window.Pagy=(()=>{const j=new ResizeObserver((B)=>B.forEach((D)=>D.target.querySelectorAll(".pagy-rjs").forEach((E)=>E.pagyRender()))),x=(B,[D,E,z,G])=>{const F=B.parentElement??B,K=Object.keys(E).map((H)=>parseInt(H)).sort((H,M)=>M-H);let L=-1;const T=(H,M,R)=>H.replace(/__pagy_page__/g,M).replace(/__pagy_label__/g,R);if((B.pagyRender=function(){const H=K.find((Q)=>Q<F.clientWidth)||0;if(H===L)return;let M=D.before;const R=E[H.toString()],X=z?.[H.toString()]??R.map((Q)=>Q.toString());R.forEach((Q,J)=>{const $=X[J];let U;if(typeof Q==="number")U=T(D.a,Q.toString(),$);else if(Q==="gap")U=D.gap;else U=T(D.current,Q,$);M+=typeof G==="string"&&Q==1?Z(U,G):U}),M+=D.after,B.innerHTML="",B.insertAdjacentHTML("afterbegin",M),L=H})(),B.classList.contains("pagy-rjs"))j.observe(F)},A=(B,[D,E])=>Y(B,(z)=>[z,D.replace(/__pagy_page__/,z)],E),C=(B,[D,E,z])=>{Y(B,(G)=>{const F=Math.max(Math.ceil(D/parseInt(G)),1).toString(),K=E.replace(/__pagy_page__/,F).replace(/__pagy_limit__/,G);return[F,K]},z)},Y=(B,D,E)=>{const z=B.querySelector("input"),G=B.querySelector("a"),F=z.value,K=function(){if(z.value===F)return;const[L,T,H]=[z.min,z.value,z.max].map((X)=>parseInt(X)||0);if(T<L||T>H){z.value=F,z.select();return}let[M,R]=D(z.value);if(typeof E==="string"&&M==="1")R=Z(R,E);G.href=R,G.click()};["change","focus"].forEach((L)=>z.addEventListener(L,()=>z.select())),z.addEventListener("focusout",K),z.addEventListener("keypress",(L)=>{if(L.key==="Enter")K()})},Z=(B,D)=>B.replace(new RegExp(`[?&]${D}=1\\b(?!&)|\\b${D}=1&`),"");return{version:"9.4.0",init(B){const E=(B instanceof Element?B:document).querySelectorAll("[data-pagy]");for(let z of E)try{const G=Uint8Array.from(atob(z.getAttribute("data-pagy")),(L)=>L.charCodeAt(0)),[F,...K]=JSON.parse(new TextDecoder().decode(G));if(F==="nav")x(z,K);else if(F==="combo")A(z,K);else if(F==="selector")C(z,K);else console.warn("Skipped Pagy.init() for: %o\nUnknown keyword '%s'",z,F)}catch(G){console.warn("Skipped Pagy.init() for: %o\n%s",z,G)}}}})();
2
2
 
3
- //# debugId=645A69572EDFDB9764756E2164756E21
3
+ //# debugId=CBA26BF804D8ECA064756E2164756E21
4
4
  //# sourceMappingURL=pagy.min.js.map
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/pagy.ts"],
4
4
  "sourcesContent": [
5
- "type NavArgs = readonly [Tokens, Sequels, null | LabelSequels, string?]\ntype ComboArgs = readonly [string, string?]\ntype SelectorArgs = readonly [number, string, string?]\ntype JsonArgs = ['nav', NavArgs] | ['combo', ComboArgs] | ['selector', SelectorArgs]\n\ninterface Tokens {\n readonly before:string\n readonly a:string\n readonly current:string\n readonly gap:string\n readonly after:string\n}\ninterface Sequels {readonly [width:string]:(string | number)[]}\ninterface LabelSequels {readonly [width:string]:string[]}\ninterface NavElement extends Element {pagyRender():void}\n\nconst Pagy = (() => {\n // The observer instance for responsive navs\n const rjsObserver = new ResizeObserver(\n entries => entries.forEach(e => e.target.querySelectorAll<NavElement>(\".pagy-rjs\")\n .forEach(el => el.pagyRender())));\n // Init the *_nav_js helpers\n const initNav = (el:NavElement, [tokens, sequels, labelSequels, trimParam]:NavArgs) => {\n const container = el.parentElement ?? el;\n const widths = Object.keys(sequels).map(w => parseInt(w)).sort((a, b) => b - a);\n let lastWidth = -1;\n const fillIn = (a:string, page:string, label:string):string =>\n a.replace(/__pagy_page__/g, page).replace(/__pagy_label__/g, label);\n (el.pagyRender = function () {\n const width = widths.find(w => w < container.clientWidth) || 0;\n if (width === lastWidth) { return } // no change: abort\n let html = tokens.before; // already trimmed in html\n const series = sequels[width.toString()];\n const labels = labelSequels?.[width.toString()] ?? series.map(l => l.toString());\n series.forEach((item, i) => {\n const label = labels[i];\n let filled;\n if (typeof item === \"number\") {\n filled = fillIn(tokens.a, item.toString(), label);\n } else if (item === \"gap\") {\n filled = tokens.gap;\n } else { // active page\n filled = fillIn(tokens.current, item, label);\n }\n html += (typeof trimParam === \"string\" && item == 1) ? trim(filled, trimParam) : filled;\n });\n html += tokens.after;\n el.innerHTML = \"\";\n el.insertAdjacentHTML(\"afterbegin\", html);\n lastWidth = width;\n })();\n if (el.classList.contains(\"pagy-rjs\")) { rjsObserver.observe(container) }\n };\n\n // Init the *_combo_nav_js helpers\n const initCombo = (el:Element, [url_token, trimParam]:ComboArgs) =>\n initInput(el, inputValue => [inputValue, url_token.replace(/__pagy_page__/, inputValue)], trimParam);\n\n // Init the limit_selector_js helper\n const initSelector = (el:Element, [from, url_token, trimParam]:SelectorArgs) => {\n initInput(el, inputValue => {\n const page = Math.max(Math.ceil(from / parseInt(inputValue)), 1).toString();\n const url = url_token.replace(/__pagy_page__/, page).replace(/__pagy_limit__/, inputValue);\n return [page, url];\n }, trimParam);\n };\n\n // Init the input element\n const initInput = (el:Element, getVars:(v:string) => [string, string], trimParam?:string) => {\n const input = el.querySelector(\"input\") as HTMLInputElement;\n const link = el.querySelector(\"a\") as HTMLAnchorElement;\n const initial = input.value;\n const action = function () {\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 let [page, url] = getVars(input.value); // eslint-disable-line prefer-const\n if (typeof trimParam === \"string\" && page === \"1\") { url = trim(url, trimParam) }\n link.href = url;\n link.click();\n };\n [\"change\", \"focus\"].forEach(e => input.addEventListener(e, () => input.select())); // auto-select\n input.addEventListener(\"focusout\", action); // trigger action\n input.addEventListener(\"keypress\", e => { if (e.key === \"Enter\") { action() } }); // trigger action\n };\n\n // Trim the ${page-param}=1 params in links\n const trim = (a:string, param:string) =>\n a.replace(new RegExp(`[?&]${param}=1\\\\b(?!&)|\\\\b${param}=1&`), \"\");\n\n // Public interface\n return {\n version: \"9.3.4\",\n\n // Scan for elements with a \"data-pagy\" attribute and call their init functions with the decoded args\n init(arg?:Element) {\n const target = arg instanceof Element ? arg : document;\n const elements = target.querySelectorAll(\"[data-pagy]\");\n for (const el of elements) {\n try {\n const uint8array = Uint8Array.from(atob(el.getAttribute(\"data-pagy\") as string), c => c.charCodeAt(0));\n const [keyword, ...args] = JSON.parse((new TextDecoder()).decode(uint8array)) as JsonArgs; // base64-utf8 -> JSON -> Array\n if (keyword === \"nav\") {\n initNav(el as NavElement, args as unknown as NavArgs);\n } else if (keyword === \"combo\") {\n initCombo(el, args as unknown as ComboArgs);\n } else if (keyword === \"selector\") {\n initSelector(el, args as unknown as SelectorArgs);\n } else {\n console.warn(\"Skipped Pagy.init() for: %o\\nUnknown keyword '%s'\", el, keyword);\n }\n } catch (err) { console.warn(\"Skipped Pagy.init() for: %o\\n%s\", el, err) }\n }\n }\n };\n})();\n\nexport default Pagy;\n"
5
+ "type NavArgs = readonly [Tokens, Sequels, null | LabelSequels, string?]\ntype ComboArgs = readonly [string, string?]\ntype SelectorArgs = readonly [number, string, string?]\ntype JsonArgs = ['nav', NavArgs] | ['combo', ComboArgs] | ['selector', SelectorArgs]\n\ninterface Tokens {\n readonly before:string\n readonly a:string\n readonly current:string\n readonly gap:string\n readonly after:string\n}\ninterface Sequels {readonly [width:string]:(string | number)[]}\ninterface LabelSequels {readonly [width:string]:string[]}\ninterface NavElement extends Element {pagyRender():void}\n\nconst Pagy = (() => {\n // The observer instance for responsive navs\n const rjsObserver = new ResizeObserver(\n entries => entries.forEach(e => e.target.querySelectorAll<NavElement>(\".pagy-rjs\")\n .forEach(el => el.pagyRender())));\n // Init the *_nav_js helpers\n const initNav = (el:NavElement, [tokens, sequels, labelSequels, trimParam]:NavArgs) => {\n const container = el.parentElement ?? el;\n const widths = Object.keys(sequels).map(w => parseInt(w)).sort((a, b) => b - a);\n let lastWidth = -1;\n const fillIn = (a:string, page:string, label:string):string =>\n a.replace(/__pagy_page__/g, page).replace(/__pagy_label__/g, label);\n (el.pagyRender = function () {\n const width = widths.find(w => w < container.clientWidth) || 0;\n if (width === lastWidth) { return } // no change: abort\n let html = tokens.before; // already trimmed in html\n const series = sequels[width.toString()];\n const labels = labelSequels?.[width.toString()] ?? series.map(l => l.toString());\n series.forEach((item, i) => {\n const label = labels[i];\n let filled;\n if (typeof item === \"number\") {\n filled = fillIn(tokens.a, item.toString(), label);\n } else if (item === \"gap\") {\n filled = tokens.gap;\n } else { // active page\n filled = fillIn(tokens.current, item, label);\n }\n html += (typeof trimParam === \"string\" && item == 1) ? trim(filled, trimParam) : filled;\n });\n html += tokens.after;\n el.innerHTML = \"\";\n el.insertAdjacentHTML(\"afterbegin\", html);\n lastWidth = width;\n })();\n if (el.classList.contains(\"pagy-rjs\")) { rjsObserver.observe(container) }\n };\n\n // Init the *_combo_nav_js helpers\n const initCombo = (el:Element, [url_token, trimParam]:ComboArgs) =>\n initInput(el, inputValue => [inputValue, url_token.replace(/__pagy_page__/, inputValue)], trimParam);\n\n // Init the limit_selector_js helper\n const initSelector = (el:Element, [from, url_token, trimParam]:SelectorArgs) => {\n initInput(el, inputValue => {\n const page = Math.max(Math.ceil(from / parseInt(inputValue)), 1).toString();\n const url = url_token.replace(/__pagy_page__/, page).replace(/__pagy_limit__/, inputValue);\n return [page, url];\n }, trimParam);\n };\n\n // Init the input element\n const initInput = (el:Element, getVars:(v:string) => [string, string], trimParam?:string) => {\n const input = el.querySelector(\"input\") as HTMLInputElement;\n const link = el.querySelector(\"a\") as HTMLAnchorElement;\n const initial = input.value;\n const action = function () {\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 let [page, url] = getVars(input.value); // eslint-disable-line prefer-const\n if (typeof trimParam === \"string\" && page === \"1\") { url = trim(url, trimParam) }\n link.href = url;\n link.click();\n };\n [\"change\", \"focus\"].forEach(e => input.addEventListener(e, () => input.select())); // auto-select\n input.addEventListener(\"focusout\", action); // trigger action\n input.addEventListener(\"keypress\", e => { if (e.key === \"Enter\") { action() } }); // trigger action\n };\n\n // Trim the ${page-param}=1 params in links\n const trim = (a:string, param:string) =>\n a.replace(new RegExp(`[?&]${param}=1\\\\b(?!&)|\\\\b${param}=1&`), \"\");\n\n // Public interface\n return {\n version: \"9.4.0\",\n\n // Scan for elements with a \"data-pagy\" attribute and call their init functions with the decoded args\n init(arg?:Element) {\n const target = arg instanceof Element ? arg : document;\n const elements = target.querySelectorAll(\"[data-pagy]\");\n for (const el of elements) {\n try {\n const uint8array = Uint8Array.from(atob(el.getAttribute(\"data-pagy\") as string), c => c.charCodeAt(0));\n const [keyword, ...args] = JSON.parse((new TextDecoder()).decode(uint8array)) as JsonArgs; // base64-utf8 -> JSON -> Array\n if (keyword === \"nav\") {\n initNav(el as NavElement, args as unknown as NavArgs);\n } else if (keyword === \"combo\") {\n initCombo(el, args as unknown as ComboArgs);\n } else if (keyword === \"selector\") {\n initSelector(el, args as unknown as SelectorArgs);\n } else {\n console.warn(\"Skipped Pagy.init() for: %o\\nUnknown keyword '%s'\", el, keyword);\n }\n } catch (err) { console.warn(\"Skipped Pagy.init() for: %o\\n%s\", el, err) }\n }\n }\n };\n})();\n\nexport default Pagy;\n"
6
6
  ],
7
7
  "mappings": "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",
8
- "debugId": "645A69572EDFDB9764756E2164756E21",
8
+ "debugId": "CBA26BF804D8ECA064756E2164756E21",
9
9
  "names": []
10
10
  }
data/javascripts/pagy.mjs CHANGED
@@ -73,7 +73,7 @@ const Pagy = (() => {
73
73
  };
74
74
  const trim = (a, param) => a.replace(new RegExp(`[?&]${param}=1\\b(?!&)|\\b${param}=1&`), "");
75
75
  return {
76
- version: "9.3.4",
76
+ version: "9.4.0",
77
77
  init(arg) {
78
78
  const target = arg instanceof Element ? arg : document;
79
79
  const elements = target.querySelectorAll("[data-pagy]");
data/lib/pagy/i18n.rb CHANGED
@@ -106,6 +106,7 @@ class Pagy
106
106
  hash['ko'] = RULE[:other]
107
107
  hash['pl'] = RULE[:polish]
108
108
  hash['ru'] = RULE[:east_slavic]
109
+ hash['sk'] = RULE[:west_slavic]
109
110
  hash['sr'] = RULE[:east_slavic]
110
111
  hash['tr'] = RULE[:other]
111
112
  hash['uk'] = RULE[:east_slavic]
@@ -10,6 +10,12 @@ class Pagy
10
10
  # Get the keyset attributes from the record
11
11
  def keyset_attributes_from(record) = record.slice(*@keyset.keys)
12
12
 
13
+ # Get the hash of quoted keyset identifiers
14
+ def quoted_identifiers(table)
15
+ connection = @set.connection
16
+ @keyset.to_h { |column| [column, "#{connection.quote_table_name(table)}.#{connection.quote_column_name(column)}"] }
17
+ end
18
+
13
19
  # Extract the keyset from the set
14
20
  def extract_keyset
15
21
  @set.order_values.each_with_object({}) do |node, keyset|
@@ -10,6 +10,12 @@ class Pagy
10
10
  # Get the keyset attributes from the record
11
11
  def keyset_attributes_from(record) = record.to_hash.slice(*@keyset.keys)
12
12
 
13
+ # Get the hash of quoted keyset identifiersAdd commentMore actions
14
+ def quoted_identifiers(table)
15
+ db = @set.db
16
+ @keyset.to_h { |column| [column, "#{db.quote_identifier(table)}.#{db.quote_identifier(column)}"] }
17
+ end
18
+
13
19
  # Extract the keyset from the set
14
20
  def extract_keyset
15
21
  return {} unless @set.opts[:order]
data/lib/pagy/keyset.rb CHANGED
@@ -90,10 +90,10 @@ class Pagy
90
90
  # with a set like Pet.order(:animal, :name, :id) it returns the following string:
91
91
  # ( "pets"."animal", "pets"."name", "pets"."id" ) > ( :animal, :name, :id )
92
92
  def filter_newest_query
93
- operator = { asc: '>', desc: '<' }
93
+ operator = { asc: '>', desc: '<' }
94
94
  directions = @keyset.values
95
- table = @set.model.table_name
96
- name = @keyset.to_h { |column| [column, %("#{table}"."#{column}")] }
95
+ name = quoted_identifiers(@set.model.table_name)
96
+
97
97
  if @vars[:tuple_comparison] && (directions.all?(:asc) || directions.all?(:desc))
98
98
  placeholders = @keyset.keys.map { |column| ":#{column}" }.join(', ')
99
99
  "( #{name.values.join(', ')} ) #{operator[directions.first]} ( #{placeholders} )"
data/lib/pagy.rb CHANGED
@@ -6,7 +6,7 @@ require_relative 'pagy/shared_methods'
6
6
 
7
7
  # Top superclass: it should define only what's common to all the subclasses
8
8
  class Pagy
9
- VERSION = '9.3.4'
9
+ VERSION = '9.4.0'
10
10
 
11
11
  # Core default: constant for easy access, but mutable for customizable defaults
12
12
  DEFAULT = { count_args: [:all], # rubocop:disable Style/MutableConstant
@@ -87,7 +87,7 @@ class Pagy
87
87
  else # intermediate pages
88
88
  @page - left
89
89
  end
90
- series.push(*start...start + size)
90
+ series.push(*start...(start + size))
91
91
  # Set first and last pages plus gaps when needed, respecting the size
92
92
  if vars[:ends] && size >= 7
93
93
  series[0] = 1
data/locales/sk.yml ADDED
@@ -0,0 +1,23 @@
1
+ # :west_slavic pluralization (see https://github.com/ddnexus/pagy/blob/master/gem/lib/pagy/i18n.rb)
2
+ sk:
3
+ pagy:
4
+ aria_label:
5
+ nav:
6
+ one: "Stránka"
7
+ few: "Stránky"
8
+ other: "Stránky"
9
+ prev: "Predchádzajúca"
10
+ next: "Ďalšia"
11
+ prev: "&lt;"
12
+ next: "&gt;"
13
+ gap: "&hellip;"
14
+ item_name:
15
+ one: "položka"
16
+ few: "položky"
17
+ other: "položiek"
18
+ info:
19
+ no_items: "Nič nebolo nájdené"
20
+ single_page: "Zobrazené %{count} %{item_name}"
21
+ multiple_pages: "Zobrazené položky %{from}-%{to} z %{count} celkom"
22
+ combo_nav_js: "Strana %{page_input} z %{pages}"
23
+ limit_selector_js: "Zobraziť %{limit_input} %{item_name} na stránke"
data/locales/ta.yml CHANGED
@@ -2,13 +2,9 @@
2
2
  ta:
3
3
  pagy:
4
4
  aria_label:
5
- # please add a comment in the https://github.com/ddnexus/pagy/issues/604
6
- # posting the translation of the following "Page"/"Pages" with the plurals for this locale
7
- # Please change the final test in 18n_loacles_test.rb to remove the ta.yml exclusion
8
- # after you make these changes.
9
- nav: "Pages"
10
- # one: ""
11
- # other: ""
5
+ nav:
6
+ one: "பக்கம்"
7
+ other: "பக்கங்கள்"
12
8
  prev: "முந்தையது"
13
9
  next: "அடுத்தது"
14
10
  prev: "&lt;"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pagy
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.3.4
4
+ version: 9.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Domizio Demichelis
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-10 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: Agnostic pagination in plain ruby. It does it all. Better.
13
13
  email:
@@ -100,6 +100,7 @@ files:
100
100
  - locales/pt-BR.yml
101
101
  - locales/pt.yml
102
102
  - locales/ru.yml
103
+ - locales/sk.yml
103
104
  - locales/sr.yml
104
105
  - locales/sv-SE.yml
105
106
  - locales/sv.yml
@@ -138,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
139
  - !ruby/object:Gem::Version
139
140
  version: '0'
140
141
  requirements: []
141
- rubygems_version: 3.6.2
142
+ rubygems_version: 3.6.7
142
143
  specification_version: 4
143
144
  summary: The best pagination ruby gem
144
145
  test_files: []