pagy 43.0.0.rc4 → 43.0.1

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: f3530078a1e8ffaaf053b808143c176431a139f2f576de4b0758e6e9cf0b9391
4
- data.tar.gz: 7512017bdf4dbedfad7ee72d1250bd3ef24133b8d255c092b84e3c0682b9e878
3
+ metadata.gz: 30ffe9d870402b6329746e4fa88b8ae4b020e5106a2fae7ac173fbb3b6ffbea1
4
+ data.tar.gz: 92cf02303244e0e261980d17004d2c13402b4f0cc8728ad4e75548e10cb62d86
5
5
  SHA512:
6
- metadata.gz: dcd6ddd5bd27e5b06f6ee9dcd1e043c1c6730240a01b0f14783c33f88e627a68a234f31d53af3d3bbb13de32c5528583532ba0a69e40dda323fa22c0692b881d
7
- data.tar.gz: 2e4d1ac8f7c78c8c8ddcba3d4477aa805884ebf8a918aa15b302d82d7cbd110564b1dccf01361a12894a14bb19a33d29bf83b927d5477844e9fa4260bd1d06d0
6
+ metadata.gz: d82757c1f5d8ac0139c67179105d86d1ff85f4c3b8fbb682fcfd046fcd331a519032e659ddb572a29427bebb6e62e78a895a8d25d18df0dbfe4019286a455140
7
+ data.tar.gz: e9891172720784f24092a58412f2ab10078d8000a31db4576cb728937bda4ea5fad8f7a370546cf102f669fe5503e690e9b2b6a0cbe43b116a810e728ab99c3c
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.0.0.rc4'
19
+ VERSION = '43.0.1'
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")
@@ -198,7 +198,6 @@ abort "ERROR: Cannot create DB files: the directory #{dir.inspect} is not writab
198
198
  unless File.writable?(dir)
199
199
  # Connection
200
200
  ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: "#{dir}/tmp/pagy-calendar.sqlite3")
201
- ActiveSupport.to_time_preserves_timezone = :zone # Fix ActiveSupport deprecation
202
201
  Date.beginning_of_week = :monday # just for rails default compatibiity
203
202
  # Groupdate initializer (https://github.com/ankane/groupdate)
204
203
  # Groupdate week_start default is :sunday, while rails and pagy default to :monday
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.0.0.rc4'
22
+ VERSION = '43.0.1'
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")
@@ -124,7 +124,7 @@ class PagyDemo < Sinatra::Base
124
124
 
125
125
  def highlight(html, format: :html)
126
126
  if format == :html
127
- html = html.gsub(/>[\s]*</, '><').strip # template single line no spaces around/between tags
127
+ html = html.gsub(/>\s*</, '><').strip # template single line no spaces around/between tags
128
128
  html = Formatter.new.format(html)
129
129
  end
130
130
  lexer = Rouge::Lexers::ERB.new
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.0.0.rc4'
19
+ VERSION = '43.0.1'
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.0.0.rc4'
19
+ VERSION = '43.0.1'
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.0.0.rc4'
19
+ VERSION = '43.0.1'
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.0.0.rc4'
19
+ VERSION = '43.0.1'
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.0.0.rc4'
19
+ VERSION = '43.0.1'
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/bin/pagy CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- VERSION = '43.0.0.rc4'
4
+ VERSION = '43.0.1'
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.0.0.rc4)
3
+ # Pagy initializer file (43.0.1)
4
4
  # See https://ddnexus.github.io/pagy/resources/initializer/
5
5
 
6
6
  ############ Global Options ################################################################
@@ -27,10 +27,10 @@
27
27
 
28
28
  ############# Overriding Pagy::I18n Lookup #################################################
29
29
  # Refer to https://ddnexus.github.io/pagy/resources/i18n/ for details.
30
- # Override the dictionary lookup for customization by dropping your customized
30
+ # Override the I18n lookup by dropping your custom dictionary in some pagy dir.
31
31
  # Example for Rails:
32
32
  #
33
- # Pagy::I18n.pathnames << Rails.root.join('config/locales')
33
+ # Pagy::I18n.pathnames << Rails.root.join('config/locales/pagy')
34
34
 
35
35
 
36
36
  ############# I18n Gem Translation #########################################################
@@ -1,23 +1,62 @@
1
- () => {
2
- function loadWidget() {
1
+ const PagyAIWidget = {
2
+ HOST_ID: 'gurubase-chat-widget-container',
3
+ IMG_SELECTOR: '#chatWindow > div.anteon-header > div > img',
4
+ NAME_SELECTOR: '#chatWindow > div.anteon-header > div > span',
5
+ DESCRIPTION_SELECTOR: '#chatWindow > div.chat-messages > div > p',
6
+ NEW_IMG_SIZE: '40px',
7
+ NEW_NAME: 'Ask Pagy AI',
8
+ NEW_DESCRIPTION: 'Pagy AI uses the latest data in the documentation to answer your questions.',
9
+ ICON_URL: 'https://github.com/ddnexus/pagy/blob/master/assets/images/pagy-the-frog.png?raw=true',
10
+
11
+ checkAndEdit: function() {
12
+ const hostElement = document.getElementById(this.HOST_ID);
13
+ if (hostElement && hostElement.shadowRoot) {
14
+ const shadowRoot = hostElement.shadowRoot;
15
+ const img = shadowRoot.querySelector(this.IMG_SELECTOR);
16
+ const name = shadowRoot.querySelector(this.NAME_SELECTOR);
17
+ const description = shadowRoot.querySelector(this.DESCRIPTION_SELECTOR);
18
+
19
+ if (img) {
20
+ img.style.maxWidth = this.NEW_IMG_SIZE;
21
+ img.style.maxHeight = this.NEW_IMG_SIZE;
22
+ }
23
+ if (name) {
24
+ name.textContent = this.NEW_NAME;
25
+ }
26
+ if (description) {
27
+ description.textContent = this.NEW_DESCRIPTION;
28
+ }
29
+ return true;
30
+ }
31
+ return false;
32
+ },
33
+
34
+ attemptEditing: function() {
35
+ if (this.checkAndEdit()) {
36
+ return;
37
+ }
38
+ setTimeout(() => this.attemptEditing(), 200);
39
+ },
40
+
41
+ editChatWidget: function() {
42
+ this.attemptEditing();
43
+ },
44
+
45
+ appendWidgetScript: function() {
3
46
  const script = document.createElement('script');
4
47
  const hostname = window.location.hostname;
5
- //const iconURL = 'https://github.com/ddnexus/pagy/blob/master/assets/images/pagy-the-frog.png?raw=true'
6
- const iconURL = 'https://github.com/ddnexus/pagy/blob/master-pre/assets/images/pagy-the-frog.png?raw=true'
48
+
7
49
  switch (hostname) {
8
50
  case 'ddnexus.github.io': // remote docs
9
- //script.dataset.widgetId = 'HKtFSPZLGiAXOdBWS4rSAxEkqv8czIbJoQdMEwCqgEc';
10
- script.dataset.widgetId = 'mH2nvQJ1iOq_Ei6ZE9ep4g-YNTHjrwZS7Cif-8uYjx4'; // pre
51
+ script.dataset.widgetId = 'HKtFSPZLGiAXOdBWS4rSAxEkqv8czIbJoQdMEwCqgEc';
11
52
  script.dataset.margins = '{"bottom": "1.48rem", "right": "6rem"}';
12
53
  break;
13
54
  case 'localhost': // local docs
14
- // script.dataset.widgetId = 'djgBhRlpdH8b07oj0Gsaerz69Xfs0FXMuUluyOo2iR4';
15
- script.dataset.widgetId = 's6flQNakiWudQCus-Z2q_8iiUSIbRm60lm2d4pc93jM'; // pre
55
+ script.dataset.widgetId = 'djgBhRlpdH8b07oj0Gsaerz69Xfs0FXMuUluyOo2iR4';
16
56
  script.dataset.margins = '{"bottom": "1.48rem", "right": "6rem"}';
17
57
  break;
18
58
  case '127.0.0.1': // apps
19
- // script.dataset.widgetId = '_rXLissYyqe-dJ9vGGGXzmJwavoW0GvuzQPEq5BZjP8';
20
- script.dataset.widgetId = 'PRTyyLAaXm1rsVnGNA964gO-iI3bRaNx7-rrcvb2ECk'; // pre
59
+ script.dataset.widgetId = '_rXLissYyqe-dJ9vGGGXzmJwavoW0GvuzQPEq5BZjP8';
21
60
  break;
22
61
  default:
23
62
  console.error('Pagy AI - Unknown hostname: ', hostname);
@@ -25,52 +64,12 @@
25
64
  script.async = true;
26
65
  script.src = 'https://widget.gurubase.io/widget.latest.min.js';
27
66
  script.id = 'guru-widget-id';
28
- script.dataset.iconUrl = iconURL; // pre
67
+ script.dataset.iconUrl = this.ICON_URL;
29
68
  script.dataset.text = 'Pagy AI';
30
69
  script.dataset.bgColor = '#1f7a1f';
31
70
  script.dataset.lightMode = 'false';
32
71
  script.dataset.tooltipSide = 'bottom';
33
72
  document.head.appendChild(script);
73
+ this.editChatWidget();
34
74
  }
35
- loadWidget();
36
-
37
- function editChatWidget() {
38
- const hostId = 'gurubase-chat-widget-container',
39
- imgSelector = '#chatWindow > div.anteon-header > div > img',
40
- nameSelector = '#chatWindow > div.anteon-header > div > span',
41
- descriptionSelector = '#chatWindow > div.chat-messages > div > p',
42
- newImgSize = '40px',
43
- newName = 'Ask Pagy AI',
44
- newDescription = 'Pagy AI uses the latest data in the documentation to answer your questions.';
45
-
46
- const checkAndEdit = () => {
47
- const hostElement = document.getElementById(hostId);
48
- if (hostElement && hostElement.shadowRoot) {
49
- const shadowRoot = hostElement.shadowRoot,
50
- img = shadowRoot.querySelector(imgSelector),
51
- name = shadowRoot.querySelector(nameSelector),
52
- description = shadowRoot.querySelector(descriptionSelector);
53
- if (img) {
54
- img.style.maxWidth = newImgSize;
55
- img.style.maxHeight = newImgSize;
56
- }
57
- if (name) {
58
- name.textContent = newName;
59
- }
60
- if (description) {
61
- description.textContent = newDescription;
62
- }
63
- return true;
64
- }
65
- return false;
66
- };
67
- const attemptEditing = () => {
68
- if (checkAndEdit()) {
69
- return;
70
- }
71
- setTimeout(attemptEditing, 200);
72
- };
73
- attemptEditing();
74
- }
75
- editChatWidget();
76
- }
75
+ };
data/javascripts/pagy.js CHANGED
@@ -124,7 +124,7 @@ window.Pagy = (() => {
124
124
  });
125
125
  };
126
126
  return {
127
- version: "43.0.0.rc4",
127
+ version: "43.0.1",
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) {
@@ -147,5 +147,5 @@ window.Pagy = (() => {
147
147
  };
148
148
  })();
149
149
 
150
- //# debugId=5BE33030F8BEBF3364756E2164756E21
150
+ //# debugId=8B68026EE11E668564756E2164756E21
151
151
  //# 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 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, pageKey, last, spliceArgs]) => {\n let augment;\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 augment = (page: string) => page + '+' + last;\n }\n }\n if (!augment) { // 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 augment = (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 // Augment the page param of each href\n for (const a of <NodeListOf<HTMLAnchorElement>><unknown>nav.querySelectorAll('a[href]')) {\n const url = a.href,\n re = new RegExp(`(?<=\\\\?.*)\\\\b${pageKey}=(\\\\d+)`); // find the numeric page from pageKey\n a.href = url.replace(re, pageKey + \"=\" + augment(url.match(re)![1])); // eslint-disable-line @typescript-eslint/no-non-null-assertion\n }\n // Return the augment function for further augmentation (i.e., url token in input_nav_js)\n return augment;\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.0.0.rc4\",\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 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, pageKey, last, spliceArgs]) => {\n let augment;\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 augment = (page: string) => page + '+' + last;\n }\n }\n if (!augment) { // 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 augment = (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 // Augment the page param of each href\n for (const a of <NodeListOf<HTMLAnchorElement>><unknown>nav.querySelectorAll('a[href]')) {\n const url = a.href,\n re = new RegExp(`(?<=\\\\?.*)\\\\b${pageKey}=(\\\\d+)`); // find the numeric page from pageKey\n a.href = url.replace(re, pageKey + \"=\" + augment(url.match(re)![1])); // eslint-disable-line @typescript-eslint/no-non-null-assertion\n }\n // Return the augment function for further augmentation (i.e., url token in input_nav_js)\n return augment;\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.0.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"
6
6
  ],
7
7
  "mappings": "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",
8
- "debugId": "5BE33030F8BEBF3364756E2164756E21",
8
+ "debugId": "8B68026EE11E668564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1 +1 @@
1
- window.Pagy=(()=>{const L="sessionStorage"in window&&"BroadcastChannel"in window;let j="pagy",Y,D,O;if(L)Y=sessionStorage,D=new BroadcastChannel(j),O=Date.now(),D.addEventListener("message",(q)=>{if(q.data.from){const z=Y.getItem(q.data.key);if(z)D.postMessage({to:q.data.from,key:q.data.key,str:z})}else if(q.data.to){if(q.data.to==O)Y.setItem(q.data.key,q.data.str)}});const U=new ResizeObserver((q)=>q.forEach((z)=>{z.target.querySelectorAll(".pagy-rjs").forEach((C)=>C.render())})),S=(q)=>btoa(String.fromCharCode(...new TextEncoder().encode(q))).replace(/[+/=]/g,(z)=>z=="+"?"-":z=="/"?"_":""),_=(q)=>new TextDecoder().decode(Uint8Array.from(atob(q),(z)=>z.charCodeAt(0))),B=()=>Math.floor(Math.random()*46656).toString(36),P=async(q,[z,C,F,G])=>{let M;const R=document.cookie.split(/;\s+/).find((H)=>H.startsWith(j+"="))?.split("=")[1]??B();if(document.cookie=j+"="+R,z&&!(z in Y)){if(D.postMessage({from:O,key:z}),await new Promise((H)=>setTimeout(()=>H(""),100)),!(z in Y))M=(H)=>H+"+"+F}if(!M){if(!z)do z=B();while(z in Y);const H=Y.getItem(z),Q=H?JSON.parse(H):[void 0];if(G)Q.splice(...G),Y.setItem(z,JSON.stringify(Q));M=(X)=>{const Z=parseInt(X);return S(JSON.stringify([R,z,Z,Q.length,Q[Z-1],Q[Z]]))}}for(let H of q.querySelectorAll("a[href]")){const Q=H.href,X=new RegExp(`(?<=\\?.*)\\b${C}=(\\d+)`);H.href=Q.replace(X,C+"="+M(Q.match(X)[1]))}return M},x=(q,[[z,C,F,G,M],[R,H,Q],X])=>{const Z=q.parentElement;let J=-1;if((q.render=()=>{const E=R.findIndex(($)=>$<Z.clientWidth);if(R[E]===J)return;let T=z;if(H[E].forEach(($,A)=>{T+=$=="gap"?G:(typeof $=="number"?C.replace("P ",$):F).replace("L<",Q?.[E][A]??$+"<")}),T+=M,q.innerHTML="",q.insertAdjacentHTML("afterbegin",T),J=R[E],X&&L)P(q,X)})(),q.classList.contains(j+"-rjs"))U.observe(Z)},N=async(q,[z,C])=>{const F=C&&L?await P(q,C):(G)=>G;W(q,(G)=>z.replace("P ",F(G)))},V=(q,[z,C])=>{W(q,(F)=>{return C.replace("P ",Math.max(Math.ceil(z/parseInt(F)),1)).replace("L ",F)})},W=(q,z)=>{const C=q.querySelector("input"),F=q.querySelector("a"),G=C.value,M=()=>{if(C.value===G)return;const[R,H,Q]=[C.min,C.value,C.max].map((X)=>parseInt(X)||0);if(H<R||H>Q){C.value=G,C.select();return}F.href=z(C.value),F.click()};C.addEventListener("focus",()=>C.select()),C.addEventListener("focusout",M),C.addEventListener("keypress",(R)=>{if(R.key=="Enter")M()})};return{version:"43.0.0.rc4",init(q){const z=q instanceof HTMLElement?q:document,C=z.querySelectorAll("[data-pagy]");for(let F of C)try{const[G,...M]=JSON.parse(_(F.getAttribute("data-pagy")));if(G=="k")P(F,...M);else if(G=="snj")x(F,M);else if(G=="inj")N(F,M);else if(G=="ltj")V(F,M)}catch(G){console.warn("Pagy.init: %o\n%s",F,G)}}}})();
1
+ window.Pagy=(()=>{const L="sessionStorage"in window&&"BroadcastChannel"in window;let j="pagy",Y,D,O;if(L)Y=sessionStorage,D=new BroadcastChannel(j),O=Date.now(),D.addEventListener("message",(q)=>{if(q.data.from){const z=Y.getItem(q.data.key);if(z)D.postMessage({to:q.data.from,key:q.data.key,str:z})}else if(q.data.to){if(q.data.to==O)Y.setItem(q.data.key,q.data.str)}});const U=new ResizeObserver((q)=>q.forEach((z)=>{z.target.querySelectorAll(".pagy-rjs").forEach((C)=>C.render())})),S=(q)=>btoa(String.fromCharCode(...new TextEncoder().encode(q))).replace(/[+/=]/g,(z)=>z=="+"?"-":z=="/"?"_":""),_=(q)=>new TextDecoder().decode(Uint8Array.from(atob(q),(z)=>z.charCodeAt(0))),B=()=>Math.floor(Math.random()*46656).toString(36),P=async(q,[z,C,F,G])=>{let M;const R=document.cookie.split(/;\s+/).find((H)=>H.startsWith(j+"="))?.split("=")[1]??B();if(document.cookie=j+"="+R,z&&!(z in Y)){if(D.postMessage({from:O,key:z}),await new Promise((H)=>setTimeout(()=>H(""),100)),!(z in Y))M=(H)=>H+"+"+F}if(!M){if(!z)do z=B();while(z in Y);const H=Y.getItem(z),Q=H?JSON.parse(H):[void 0];if(G)Q.splice(...G),Y.setItem(z,JSON.stringify(Q));M=(X)=>{const Z=parseInt(X);return S(JSON.stringify([R,z,Z,Q.length,Q[Z-1],Q[Z]]))}}for(let H of q.querySelectorAll("a[href]")){const Q=H.href,X=new RegExp(`(?<=\\?.*)\\b${C}=(\\d+)`);H.href=Q.replace(X,C+"="+M(Q.match(X)[1]))}return M},x=(q,[[z,C,F,G,M],[R,H,Q],X])=>{const Z=q.parentElement;let J=-1;if((q.render=()=>{const E=R.findIndex(($)=>$<Z.clientWidth);if(R[E]===J)return;let T=z;if(H[E].forEach(($,A)=>{T+=$=="gap"?G:(typeof $=="number"?C.replace("P ",$):F).replace("L<",Q?.[E][A]??$+"<")}),T+=M,q.innerHTML="",q.insertAdjacentHTML("afterbegin",T),J=R[E],X&&L)P(q,X)})(),q.classList.contains(j+"-rjs"))U.observe(Z)},N=async(q,[z,C])=>{const F=C&&L?await P(q,C):(G)=>G;W(q,(G)=>z.replace("P ",F(G)))},V=(q,[z,C])=>{W(q,(F)=>{return C.replace("P ",Math.max(Math.ceil(z/parseInt(F)),1)).replace("L ",F)})},W=(q,z)=>{const C=q.querySelector("input"),F=q.querySelector("a"),G=C.value,M=()=>{if(C.value===G)return;const[R,H,Q]=[C.min,C.value,C.max].map((X)=>parseInt(X)||0);if(H<R||H>Q){C.value=G,C.select();return}F.href=z(C.value),F.click()};C.addEventListener("focus",()=>C.select()),C.addEventListener("focusout",M),C.addEventListener("keypress",(R)=>{if(R.key=="Enter")M()})};return{version:"43.0.1",init(q){const z=q instanceof HTMLElement?q:document,C=z.querySelectorAll("[data-pagy]");for(let F of C)try{const[G,...M]=JSON.parse(_(F.getAttribute("data-pagy")));if(G=="k")P(F,...M);else if(G=="snj")x(F,M);else if(G=="inj")N(F,M);else if(G=="ltj")V(F,M)}catch(G){console.warn("Pagy.init: %o\n%s",F,G)}}}})();
data/javascripts/pagy.mjs CHANGED
@@ -123,7 +123,7 @@ const Pagy = (() => {
123
123
  });
124
124
  };
125
125
  return {
126
- version: "43.0.0.rc4",
126
+ version: "43.0.1",
127
127
  init(arg) {
128
128
  const target = arg instanceof HTMLElement ? arg : document, elements = target.querySelectorAll("[data-pagy]");
129
129
  for (const element of elements) {
@@ -54,7 +54,7 @@ class Pagy
54
54
  conf[unit][:period] = object&.send(:active_period) || @period
55
55
  conf[unit][:page] = page_keys["#{unit}_#{@page_key}"] \
56
56
  = create(unit, **conf[unit]).send(:page_at, time, **)
57
- conf[unit][:querify] = ->(query) { query.merge!(page_keys) }
57
+ conf[unit][:querify] = ->(params) { params.merge!(page_keys) }
58
58
  create(unit, **conf[unit])
59
59
  end.send(:compose_page_url, 1, **)
60
60
  end
@@ -62,11 +62,11 @@ class Pagy
62
62
  private
63
63
 
64
64
  # Create the calendar
65
- def init(conf, period, query)
65
+ def init(conf, period, params)
66
66
  @conf = Marshal.load(Marshal.dump(conf)) # store a copy
67
67
  @units = Calendar::UNITS & @conf.keys # get the units in time length desc order
68
68
  @period = period
69
- @query = query
69
+ @params = params
70
70
  @page_key = conf[:offset][:page_key] || DEFAULT[:page_key]
71
71
  # set all the :page_key options for later deletion
72
72
  @units.each { |unit| conf[unit][:page_key] = "#{unit}_#{@page_key}" }
@@ -76,7 +76,7 @@ class Pagy
76
76
  params_to_delete = @units[(index + 1), @units.length].map { |sub| conf[sub][:page_key] } + [@page_key]
77
77
  conf[unit][:querify] = ->(up) { up.except!(*params_to_delete.map(&:to_s)) }
78
78
  conf[unit][:period] = object&.send(:active_period) || @period
79
- conf[unit][:page] = @query["#{unit}_#{@page_key}"] # requested page
79
+ conf[unit][:page] = @params["#{unit}_#{@page_key}"] # requested page
80
80
  # :nocov:
81
81
  # simplecov doesn't need to fail block_given?
82
82
  conf[unit][:counts] = yield(unit, conf[unit][:period]) if block_given?
@@ -27,6 +27,7 @@ class Pagy
27
27
  end
28
28
 
29
29
  attr_reader :order, :from, :to, :previous, :last
30
+ alias pages last
30
31
 
31
32
  protected
32
33
 
@@ -22,6 +22,7 @@ class Pagy
22
22
  end
23
23
 
24
24
  attr_reader :update, :previous, :last
25
+ alias pages last
25
26
 
26
27
  # Prepare the @update for the client when it's a new page, and return the next page number
27
28
  def next
@@ -27,6 +27,7 @@ class Pagy
27
27
  end
28
28
 
29
29
  attr_reader :offset, :count, :from, :to, :in, :previous, :last
30
+ alias pages last
30
31
 
31
32
  def records(collection)
32
33
  collection.offset(@offset).limit(@limit)
@@ -3,23 +3,24 @@
3
3
  class Pagy
4
4
  # Decouple the reuest from the env, allowing non-rack apps to use pagy by passing a hash.
5
5
  # Resolve :page and :limit, supporting the :jsonapi option. Support for URL composition.
6
+ #
6
7
  class Request
7
8
  def initialize(request, options = {})
8
- @base_url, @path, @query, @cookie =
9
+ @base_url, @path, @params, @cookie =
9
10
  if request.is_a?(Hash)
10
- request.values_at(:base_url, :path, :query, :cookie)
11
+ request.values_at(:base_url, :path, :params, :cookie)
11
12
  else
12
- [request.base_url, request.path, request.GET, request.cookies['pagy']]
13
+ [request.base_url, request.path, request.params, request.cookies['pagy']]
13
14
  end
14
- @jsonapi = @query['page'] && options[:jsonapi]
15
- raise JsonapiReservedParamError, @query['page'] if @jsonapi && !@query['page'].respond_to?(:fetch)
15
+ @jsonapi = @params['page'] && options[:jsonapi]
16
+ raise JsonapiReservedParamError, @params['page'] if @jsonapi && !@params['page'].respond_to?(:fetch)
16
17
  end
17
18
 
18
- attr_reader :base_url, :path, :query, :cookie
19
+ attr_reader :base_url, :path, :params, :cookie
19
20
 
20
21
  def resolve_page(options, force_integer: true)
21
22
  page_key = options[:page_key] || DEFAULT[:page_key]
22
- page = @jsonapi ? @query['page'][page_key] : @query[page_key]
23
+ page = @jsonapi ? @params['page'][page_key] : @params[page_key]
23
24
  page = nil if page == '' # fix for app-generated queries like ?page=
24
25
  force_integer ? (page || 1).to_i : page
25
26
  end
@@ -28,7 +29,7 @@ class Pagy
28
29
  limit_key = options[:limit_key] || DEFAULT[:limit_key]
29
30
  return options[:limit] || DEFAULT[:limit] \
30
31
  unless options[:client_max_limit] &&
31
- (requested_limit = @jsonapi ? @query['page'][limit_key] : @query[limit_key])
32
+ (requested_limit = @jsonapi ? @params['page'][limit_key] : @params[limit_key])
32
33
 
33
34
  [requested_limit.to_i, options[:client_max_limit]].min
34
35
  end
@@ -15,7 +15,12 @@ class Pagy
15
15
  def dev_tools(wand_scale: 1)
16
16
  <<~HTML
17
17
  <script id="pagy-ai-widget">
18
- document.addEventListener('wand-positioned', #{ROOT.join('javascripts/ai_widget.js').read});
18
+ #{ROOT.join('javascripts/ai_widget.js').read}
19
+ document.addEventListener('wand-positioned', PagyAIWidget.appendWidgetScript );
20
+ document.addEventListener('turbo:load', () => {
21
+ window.chatWidget = new ChatWidget();
22
+ PagyAIWidget.editChatWidget();
23
+ };
19
24
  </script>
20
25
  <script id="pagy-wand" data-scale="#{wand_scale}">
21
26
  #{ROOT.join('javascripts/wand.js').read}
@@ -43,15 +43,15 @@ class Pagy
43
43
  jsonapi, page_key, limit_key, limit, client_max_limit, querify, absolute, path, fragment =
44
44
  @options.merge(options)
45
45
  .values_at(:jsonapi, :page_key, :limit_key, :limit, :client_max_limit, :querify, :absolute, :path, :fragment)
46
- query = @request.query.clone(freeze: false)
47
- query.delete(jsonapi ? 'page' : page_key)
46
+ params = @request.params.clone(freeze: false)
47
+ params.delete(jsonapi ? 'page' : page_key)
48
48
  factors = {}.tap do |h|
49
49
  h[page_key] = countless? ? "#{page || 1}+#{@last}" : page
50
50
  h[limit_key] = limit_token || limit if client_max_limit
51
51
  end.compact # No empty params
52
- query.merge!(jsonapi ? { 'page' => factors } : factors) if factors.size.positive?
53
- querify&.(query) # Must modify the query: the returned value is ignored
54
- query_string = QueryUtils.build_nested_query(query, nil, [page_key, limit_key])
52
+ params.merge!(jsonapi ? { 'page' => factors } : factors) if factors.size.positive?
53
+ querify&.(params) # Must modify the params: the returned value is ignored
54
+ query_string = QueryUtils.build_nested_query(params, nil, [page_key, limit_key])
55
55
  query_string = "?#{query_string}" unless query_string.empty?
56
56
  fragment &&= %(##{fragment}) unless fragment&.start_with?('#')
57
57
  "#{@request.base_url if absolute}#{path || @request.path}#{query_string}#{fragment}"
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Pagy
4
+ DEFAULT_DATA_KEYS = %i[url_template first_url previous_url page_url next_url last_url
5
+ count page limit last in from to previous next options].freeze
6
+
4
7
  # Generate a hash of the wanted internal data
5
- def data_hash(data_keys: @options[:data_keys] ||
6
- %i[url_template first_url previous_url page_url next_url last_url
7
- count page limit last in from to previous next options], **)
8
+ def data_hash(data_keys: @options[:data_keys] || DEFAULT_DATA_KEYS, **)
8
9
  data_keys -= %i[count limit] if calendar?
9
10
  url_template = compose_page_url(PAGE_TOKEN, **)
10
11
  {}.tap do |data|
@@ -4,17 +4,21 @@ require_relative 'urls_hash'
4
4
 
5
5
  # Add pagination response headers
6
6
  class Pagy
7
+ DEFAULT_HEADERS_MAP = { page: 'current-page',
8
+ limit: 'page-limit',
9
+ count: 'total-count',
10
+ pages: 'total-pages' }.freeze
11
+
7
12
  # Generate a hash of RFC-8288-compliant http headers
8
- def headers_hash(headers_map: @options[:headers_map] ||
9
- { page: 'current-page', limit: 'page-limit', count: 'total-count', pages: 'total-pages' }, **)
13
+ def headers_hash(headers_map: @options[:headers_map] || DEFAULT_HEADERS_MAP, **)
10
14
  links = urls_hash(**, absolute: true).map { |key, url| %(<#{url}>; rel="#{key}") }.join(', ')
11
15
  { 'link' => links }.tap do |hash|
12
16
  hash[headers_map[:page]] = @page.to_s if @page && headers_map[:page]
13
17
  hash[headers_map[:limit]] = @limit.to_s if headers_map[:limit] && !calendar?
14
- return hash unless @count
15
-
16
- hash[headers_map[:pages]] = @last.to_s if headers_map[:pages]
17
- hash[headers_map[:count]] = @count.to_s if headers_map[:count]
18
+ if @count
19
+ hash[headers_map[:pages]] = @last.to_s if headers_map[:pages]
20
+ hash[headers_map[:count]] = @count.to_s if headers_map[:count]
21
+ end
18
22
  end
19
23
  end
20
24
  end
@@ -3,7 +3,7 @@
3
3
  require_relative 'support/wrap_input_nav_js'
4
4
 
5
5
  class Pagy
6
- # Javascript combo pagination: it returns a nav with a data-pagy attribute used by the pagy.js file
6
+ # JavaScript input pagination: it returns a nav with a data-pagy attribute used by the pagy.js file
7
7
  def input_nav_js(style = nil, **)
8
8
  return send(:"#{style}_input_nav_js", **) if style
9
9
 
@@ -15,5 +15,4 @@ class Pagy
15
15
  next_tag(a_lambda)})
16
16
  wrap_input_nav_js(html, 'pagy input-nav-js', **)
17
17
  end
18
- alias pagy_input_nav_js input_nav_js
19
18
  end
@@ -3,7 +3,7 @@
3
3
  require_relative 'support/wrap_series_nav'
4
4
 
5
5
  class Pagy
6
- # Return the html with the series of links to the pages
6
+ # Return the HTML with the series of links to the pages
7
7
  def series_nav(style = nil, **)
8
8
  return send(:"#{style}_series_nav", **) if style
9
9
 
@@ -25,5 +25,4 @@ class Pagy
25
25
  html << next_tag(a_lambda)
26
26
  wrap_series_nav(html, 'pagy series-nav', **)
27
27
  end
28
- alias pagy_series_nav series_nav
29
28
  end
@@ -15,5 +15,4 @@ class Pagy
15
15
  after: next_tag(a_lambda) }
16
16
  wrap_series_nav_js(tokens, 'pagy series-nav-js', **)
17
17
  end
18
- alias pagy_series_nav_js series_nav_js
19
18
  end
@@ -17,7 +17,7 @@ class Pagy
17
17
  calendar, from, to =
18
18
  Calendar.send(:init, config,
19
19
  pagy_calendar_period(collection),
20
- config[:request].query) do |unit, period|
20
+ config[:request].params) do |unit, period|
21
21
  pagy_calendar_counts(collection, unit, *period) if respond_to?(:pagy_calendar_counts)
22
22
  end
23
23
  collection = pagy_calendar_filter(collection, from, to)
@@ -6,7 +6,7 @@ class Pagy
6
6
  module ElasticsearchRailsPaginator
7
7
  module_function
8
8
 
9
- # Paginate from search object
9
+ # Paginate from the search object
10
10
  def paginate(context, search, **options)
11
11
  context.instance_eval do
12
12
  if search.is_a?(Search::Arguments)
@@ -6,7 +6,7 @@ class Pagy
6
6
  module MeilisearchPaginator
7
7
  module_function
8
8
 
9
- # Paginate from search object
9
+ # Paginate from the search object
10
10
  def paginate(context, search, **options)
11
11
  context.instance_eval do
12
12
  if search.is_a?(Search::Arguments)
@@ -6,7 +6,7 @@ class Pagy
6
6
  module SearchkickPaginator
7
7
  module_function
8
8
 
9
- # Paginate from search object.
9
+ # Paginate from the search object
10
10
  def paginate(context, search, **options)
11
11
  context.instance_eval do
12
12
  if search.is_a?(Search::Arguments)
data/lib/pagy.rb CHANGED
@@ -8,7 +8,7 @@ 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
- VERSION = '43.0.0.rc4'
11
+ VERSION = '43.0.1'
12
12
  ROOT = Pathname.new(__dir__).parent.freeze
13
13
  DEFAULT = { limit: 20, limit_key: 'limit', page_key: 'page' }.freeze
14
14
  PAGE_TOKEN = 'P '
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.0.0.rc4
4
+ version: 43.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Domizio Demichelis
@@ -184,7 +184,7 @@ metadata:
184
184
  homepage_uri: https://github.com/ddnexus/pagy
185
185
  documentation_uri: https://ddnexus.github.io/pagy
186
186
  bug_tracker_uri: https://github.com/ddnexus/pagy/issues
187
- changelog_uri: https://github.com/ddnexus/pagy/blob/master/CHANGELOG.md
187
+ changelog_uri: https://ddnexus.github.io/pagy/changelog/
188
188
  support: https://github.com/ddnexus/pagy/discussions/categories/q-a
189
189
  rdoc_options: []
190
190
  require_paths: