@schukai/monster 3.95.1 → 3.95.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.
@@ -13,32 +13,32 @@
13
13
  */
14
14
 
15
15
  import {
16
- assembleMethodSymbol,
17
- CustomElement,
18
- registerCustomElement,
16
+ assembleMethodSymbol,
17
+ CustomElement,
18
+ registerCustomElement,
19
19
  } from "../../dom/customelement.mjs";
20
- import { findElementWithSelectorUpwards, getWindow } from "../../dom/util.mjs";
21
- import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
22
- import { ThemeStyleSheet } from "../stylesheet/theme.mjs";
23
- import { ATTRIBUTE_DATASOURCE_SELECTOR } from "./constants.mjs";
24
- import { Datasource } from "./datasource.mjs";
25
- import { Observer } from "../../types/observer.mjs";
26
- import { ATTRIBUTE_ROLE } from "../../dom/constants.mjs";
27
- import { findTargetElementFromEvent } from "../../dom/events.mjs";
28
- import { PaginationStyleSheet } from "./stylesheet/pagination.mjs";
29
- import { DisplayStyleSheet } from "../stylesheet/display.mjs";
30
- import { isString } from "../../types/is.mjs";
31
- import { Pathfinder } from "../../data/pathfinder.mjs";
32
- import { instanceSymbol } from "../../constants.mjs";
33
- import { Formatter } from "../../text/formatter.mjs";
20
+ import {findElementWithSelectorUpwards, getWindow} from "../../dom/util.mjs";
21
+ import {DeadMansSwitch} from "../../util/deadmansswitch.mjs";
22
+ import {ThemeStyleSheet} from "../stylesheet/theme.mjs";
23
+ import {ATTRIBUTE_DATASOURCE_SELECTOR} from "./constants.mjs";
24
+ import {Datasource} from "./datasource.mjs";
25
+ import {Observer} from "../../types/observer.mjs";
26
+ import {ATTRIBUTE_ROLE} from "../../dom/constants.mjs";
27
+ import {findTargetElementFromEvent} from "../../dom/events.mjs";
28
+ import {PaginationStyleSheet} from "./stylesheet/pagination.mjs";
29
+ import {DisplayStyleSheet} from "../stylesheet/display.mjs";
30
+ import {isString} from "../../types/is.mjs";
31
+ import {Pathfinder} from "../../data/pathfinder.mjs";
32
+ import {instanceSymbol} from "../../constants.mjs";
33
+ import {Formatter} from "../../text/formatter.mjs";
34
34
  import "../form/select.mjs";
35
- import { addAttributeToken } from "../../dom/attributes.mjs";
36
- import { ATTRIBUTE_ERRORMESSAGE } from "../../dom/constants.mjs";
35
+ import {addAttributeToken} from "../../dom/attributes.mjs";
36
+ import {ATTRIBUTE_ERRORMESSAGE} from "../../dom/constants.mjs";
37
37
 
38
38
  import "./datasource/dom.mjs";
39
39
  import "./datasource/rest.mjs";
40
40
 
41
- export { Pagination };
41
+ export {Pagination};
42
42
 
43
43
  /**
44
44
  * @private
@@ -71,215 +71,227 @@ const sizeDataSymbol = Symbol("sizeData");
71
71
  const debounceSizeSymbol = Symbol("debounceSize");
72
72
 
73
73
  /**
74
- * The Pagination component
74
+ * A Pagination component
75
+ *
76
+ * @fragments /fragments/components/datatable/pagination
77
+ *
78
+ * @example /examples/components/datatable/pagination-simple
75
79
  *
76
80
  * @copyright schukai GmbH
77
81
  * @summary The Pagination component is used to show the current page and the total number of pages.
78
82
  */
79
83
  class Pagination extends CustomElement {
80
- /**
81
- */
82
- constructor() {
83
- super();
84
- this[datasourceLinkedElementSymbol] = null;
85
- }
86
-
87
- /**
88
- * This method is called by the `instanceof` operator.
89
- * @return {symbol}
90
- */
91
- static get [instanceSymbol]() {
92
- return Symbol.for("@schukai/monster/components/pagination");
93
- }
94
-
95
- /**
96
- * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
97
- * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
98
- *
99
- * The individual configuration values can be found in the table.
100
- *
101
- * @property {Object} templates Template definitions
102
- * @property {string} templates.main Main template
103
- * @property {Object} datasource Datasource configuration
104
- * @property {string} datasource.selector Datasource selector
105
- * @property {Object} labels Label definitions
106
- * @property {string} labels.page Page label
107
- * @property {string} labels.description Description label
108
- * @property {string} labels.previous Previous label
109
- * @property {string} labels.next Next label
110
- * @property {string} labels.of Of label
111
- * @property {string} href Href
112
- * @property {number} currentPage Current page
113
- * @property {number} pages Pages
114
- * @property {number} objectsPerPage Objects per page
115
- * @property {Object} mapping Mapping
116
- * @property {string} mapping.pages Pages mapping
117
- * @property {string} mapping.objectsPerPage Objects per page mapping
118
- * @property {string} mapping.currentPage Current page mapping
119
- * @property {Object} pagination Pagination
120
- */
121
- get defaults() {
122
- return Object.assign(
123
- {},
124
- super.defaults,
125
- {
126
- templates: {
127
- main: getTemplate(),
128
- },
129
-
130
- datasource: {
131
- selector: null,
132
- },
133
-
134
- labels: {
135
- page: "${page}",
136
- description: "Page ${page}",
137
- previous: "Previous",
138
- next: "Next",
139
- of: "of",
140
- },
141
-
142
- href: "page-${page}",
143
-
144
- currentPage: undefined,
145
- pages: undefined,
146
- objectsPerPage: 20,
147
-
148
- mapping: {
149
- pages: "sys.pagination.pages",
150
- objectsPerPage: "sys.pagination.objectsPerPage",
151
- currentPage: "sys.pagination.currentPage",
152
- },
153
-
154
- pagination: {
155
- items: [],
156
- },
157
- },
158
- initOptionsFromArguments.call(this),
159
- );
160
- }
161
-
162
- /**
163
- *
164
- * @return {string}
165
- */
166
- static getTag() {
167
- return "monster-pagination";
168
- }
169
-
170
- /**
171
- * @return {void}
172
- */
173
- disconnectedCallback() {
174
- super.disconnectedCallback();
175
- if (this?.[resizeObserverSymbol] instanceof ResizeObserver) {
176
- this[resizeObserverSymbol].disconnect();
177
- }
178
- }
179
-
180
- /**
181
- * @return {void}
182
- */
183
- connectedCallback() {
184
- super.connectedCallback();
185
-
186
- const parentNode = this.parentNode;
187
- if (!parentNode) {
188
- return;
189
- }
190
-
191
- const parentParentNode = parentNode?.parentNode || parentNode;
192
-
193
- const parentWidth = parentParentNode.offsetWidth;
194
- const ownWidth = this.offsetWidth;
195
-
196
- this[sizeDataSymbol] = {
197
- last: {
198
- parentWidth: parentParentNode.offsetWidth || 0,
199
- },
200
- showNumbers: ownWidth < parentWidth,
201
- };
202
-
203
- handleDataSourceChanges.call(this);
204
-
205
- setTimeout(() => {
206
- this[resizeObserverSymbol] = new ResizeObserver((entries) => {
207
- if (this[debounceSizeSymbol] instanceof DeadMansSwitch) {
208
- try {
209
- this[debounceSizeSymbol].touch();
210
- return;
211
- } catch (e) {
212
- delete this[debounceSizeSymbol];
213
- }
214
- }
215
-
216
- this[debounceSizeSymbol] = new DeadMansSwitch(250, () => {
217
- queueMicrotask(() => {
218
- const parentWidth = parentParentNode.offsetWidth;
219
- const ownWidth = this.clientWidth;
220
-
221
- if (this[sizeDataSymbol]?.last?.parentWidth === parentWidth) {
222
- return;
223
- }
224
-
225
- this[sizeDataSymbol].last = {
226
- parentWidth: parentWidth,
227
- };
228
-
229
- this[sizeDataSymbol].showNumbers = ownWidth < parentWidth;
230
- handleDataSourceChanges.call(this);
231
- });
232
- });
233
- });
234
-
235
- this[resizeObserverSymbol].observe(this?.parentNode?.parentNode);
236
- }, 500);
237
- }
238
-
239
- /**
240
- * @return {void}
241
- */
242
- [assembleMethodSymbol]() {
243
- super[assembleMethodSymbol]();
244
-
245
- initControlReferences.call(this);
246
- initEventHandler.call(this);
247
-
248
- const selector = this.getOption("datasource.selector", "");
249
-
250
- if (isString(selector)) {
251
- const element = findElementWithSelectorUpwards(this, selector);
252
- if (element === null) {
253
- throw new Error("the selector must match exactly one element");
254
- }
255
-
256
- if (!(element instanceof Datasource)) {
257
- throw new TypeError("the element must be a datasource");
258
- }
259
-
260
- this[datasourceLinkedElementSymbol] = element;
261
- element.datasource.attachObserver(
262
- new Observer(handleDataSourceChanges.bind(this)),
263
- );
264
-
265
- handleDataSourceChanges.call(this);
266
- }
267
- }
268
-
269
- /**
270
- * @private
271
- * @return {CSSStyleSheet}
272
- */
273
- static getControlCSSStyleSheet() {
274
- return PaginationStyleSheet;
275
- }
276
-
277
- /**
278
- * @return {CSSStyleSheet[]}
279
- */
280
- static getCSSStyleSheet() {
281
- return [this.getControlCSSStyleSheet(), DisplayStyleSheet, ThemeStyleSheet];
282
- }
84
+ /**
85
+ */
86
+ constructor() {
87
+ super();
88
+ this[datasourceLinkedElementSymbol] = null;
89
+ }
90
+
91
+ /**
92
+ * This method is called by the `instanceof` operator.
93
+ * @return {symbol}
94
+ */
95
+ static get [instanceSymbol]() {
96
+ return Symbol.for("@schukai/monster/components/pagination");
97
+ }
98
+
99
+ /**
100
+ * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
101
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
102
+ *
103
+ * The individual configuration values can be found in the table.
104
+ *
105
+ * @property {Object} templates Template definitions
106
+ * @property {string} templates.main Main template
107
+ * @property {Object} datasource Datasource configuration
108
+ * @property {string} datasource.selector Datasource selector
109
+ * @property {Object} labels Label definitions
110
+ * @property {string} labels.page Page label
111
+ * @property {string} labels.description Description label
112
+ * @property {string} labels.previous Previous label
113
+ * @property {string} labels.next Next label
114
+ * @property {string} labels.of Of label
115
+ * @property {string} href Href
116
+ * @property {number} currentPage Current page
117
+ * @property {number} pages Pages
118
+ * @property {number} objectsPerPage Objects per page
119
+ * @property {Object} mapping Mapping
120
+ * @property {string} mapping.pages Pages mapping
121
+ * @property {string} mapping.objectsPerPage Objects per page mapping
122
+ * @property {string} mapping.currentPage Current page mapping
123
+ */
124
+ get defaults() {
125
+ return Object.assign(
126
+ {},
127
+ super.defaults,
128
+ {
129
+ templates: {
130
+ main: getTemplate(),
131
+ },
132
+
133
+ datasource: {
134
+ selector: null,
135
+ },
136
+
137
+ labels: {
138
+ page: "${page}",
139
+ description: "Page ${page}",
140
+ previous: "Previous",
141
+ next: "Next",
142
+ of: "of",
143
+ },
144
+
145
+ href: "page-${page}",
146
+
147
+ pages: null,
148
+ objectsPerPage: 20,
149
+ currentPage: null,
150
+
151
+ mapping: {
152
+ pages: "sys.pagination.pages",
153
+ objectsPerPage: "sys.pagination.objectsPerPage",
154
+ currentPage: "sys.pagination.currentPage",
155
+ },
156
+
157
+ /* @private */
158
+ pagination: {
159
+ items: [],
160
+ },
161
+ },
162
+ initOptionsFromArguments.call(this),
163
+ );
164
+ }
165
+
166
+ /**
167
+ *
168
+ * @return {string}
169
+ */
170
+ static getTag() {
171
+ return "monster-pagination";
172
+ }
173
+
174
+ /**
175
+ * @return {void}
176
+ */
177
+ disconnectedCallback() {
178
+ super.disconnectedCallback();
179
+ if (this?.[resizeObserverSymbol] instanceof ResizeObserver) {
180
+ this[resizeObserverSymbol].disconnect();
181
+ }
182
+ }
183
+
184
+ /**
185
+ * @return {void}
186
+ */
187
+ connectedCallback() {
188
+ super.connectedCallback();
189
+
190
+ const parentNode = this.parentNode;
191
+ if (!parentNode) {
192
+ return;
193
+ }
194
+
195
+ try {
196
+ handleDataSourceChanges.call(this);
197
+ } catch (e) {
198
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e?.message || `${e}`);
199
+ }
200
+
201
+ requestAnimationFrame(() => {
202
+ const parentParentNode = parentNode?.parentNode || parentNode;
203
+
204
+ const parentWidth = parentParentNode.offsetWidth;
205
+ const ownWidth = this.offsetWidth;
206
+
207
+ this[sizeDataSymbol] = {
208
+ last: {
209
+ parentWidth: 0,
210
+ },
211
+ showNumbers: ownWidth < parentWidth,
212
+ };
213
+
214
+ this[resizeObserverSymbol] = new ResizeObserver((entries) => {
215
+ if (this[debounceSizeSymbol] instanceof DeadMansSwitch) {
216
+ try {
217
+ this[debounceSizeSymbol].touch();
218
+ return;
219
+ } catch (e) {
220
+ delete this[debounceSizeSymbol];
221
+ }
222
+ }
223
+
224
+ this[debounceSizeSymbol] = new DeadMansSwitch(250, () => {
225
+ queueMicrotask(() => {
226
+ const parentWidth = parentParentNode.offsetWidth;
227
+ const ownWidth = this.clientWidth;
228
+
229
+ if (this[sizeDataSymbol]?.last?.parentWidth === parentWidth) {
230
+ return;
231
+ }
232
+
233
+ this[sizeDataSymbol].last = {
234
+ parentWidth: parentWidth,
235
+ };
236
+
237
+ this[sizeDataSymbol].showNumbers = ownWidth <= parentWidth;
238
+ handleDataSourceChanges.call(this);
239
+ });
240
+ });
241
+ });
242
+
243
+ this[resizeObserverSymbol].observe(this?.parentNode?.parentNode);
244
+ });
245
+ }
246
+
247
+ /**
248
+ * @return {void}
249
+ */
250
+ [assembleMethodSymbol]() {
251
+ super[assembleMethodSymbol]();
252
+
253
+ initControlReferences.call(this);
254
+ initEventHandler.call(this);
255
+
256
+ const selector = this.getOption("datasource.selector", "");
257
+
258
+ if (isString(selector)) {
259
+ const element = findElementWithSelectorUpwards(this, selector);
260
+ if (element === null) {
261
+ throw new Error("the selector must match exactly one element");
262
+ }
263
+
264
+ if (!(element instanceof Datasource)) {
265
+ throw new TypeError("the element must be a datasource");
266
+ }
267
+
268
+ this[datasourceLinkedElementSymbol] = element;
269
+ element.datasource.attachObserver(
270
+ new Observer(handleDataSourceChanges.bind(this)),
271
+ );
272
+
273
+ element.attachObserver(
274
+ new Observer(handleDataSourceChanges.bind(this)),
275
+ );
276
+
277
+ handleDataSourceChanges.call(this);
278
+ }
279
+ }
280
+
281
+ /**
282
+ * @private
283
+ * @return {CSSStyleSheet}
284
+ */
285
+ static getControlCSSStyleSheet() {
286
+ return PaginationStyleSheet;
287
+ }
288
+
289
+ /**
290
+ * @return {CSSStyleSheet[]}
291
+ */
292
+ static getCSSStyleSheet() {
293
+ return [this.getControlCSSStyleSheet(), DisplayStyleSheet, ThemeStyleSheet];
294
+ }
283
295
  }
284
296
 
285
297
  /**
@@ -288,87 +300,88 @@ class Pagination extends CustomElement {
288
300
  * @throws {Error} no shadow-root is defined
289
301
  */
290
302
  function initControlReferences() {
291
- if (!this.shadowRoot) {
292
- throw new Error("no shadow-root is defined");
293
- }
303
+ if (!this.shadowRoot) {
304
+ throw new Error("no shadow-root is defined");
305
+ }
294
306
 
295
- this[paginationElementSymbol] = this.shadowRoot.querySelector(
296
- "[data-monster-role=pagination]",
297
- );
307
+ this[paginationElementSymbol] = this.shadowRoot.querySelector(
308
+ "[data-monster-role=pagination]",
309
+ );
298
310
  }
299
311
 
300
312
  /**
301
313
  * @private
302
314
  */
303
315
  function initEventHandler() {
304
- const self = this;
305
-
306
- self[paginationElementSymbol].addEventListener("click", function (event) {
307
- let element = null;
308
- const datasource = self[datasourceLinkedElementSymbol];
309
- if (!datasource) {
310
- return;
311
- }
312
-
313
- element = findTargetElementFromEvent(
314
- event,
315
- ATTRIBUTE_ROLE,
316
- "pagination-item",
317
- );
318
- if (!element) {
319
- element = findTargetElementFromEvent(
320
- event,
321
- ATTRIBUTE_ROLE,
322
- "pagination-next",
323
- );
324
- if (!element) {
325
- element = findTargetElementFromEvent(
326
- event,
327
- ATTRIBUTE_ROLE,
328
- "pagination-prev",
329
- );
330
- if (!element) {
331
- return;
332
- }
333
- }
334
- }
335
-
336
- if (!(element instanceof HTMLElement)) {
337
- return;
338
- }
339
-
340
- let page = null;
341
-
342
- if (!element.hasAttribute("data-page-no")) {
343
- return;
344
- }
345
-
346
- page = element.getAttribute("data-page-no");
347
- event.preventDefault();
348
-
349
- if (
350
- !page ||
351
- page === "" ||
352
- page === null ||
353
- page === undefined ||
354
- page === "undefined" ||
355
- page === "null"
356
- ) {
357
- return;
358
- }
359
-
360
- if (typeof datasource.setParameters !== "function") {
361
- return;
362
- }
363
-
364
- datasource.setParameters({ page });
365
-
366
- if (typeof datasource.reload !== "function") {
367
- return;
368
- }
369
-
370
- datasource.reload();
371
- });
316
+ const self = this;
317
+
318
+ self[paginationElementSymbol].addEventListener("click", function (event) {
319
+ let element = null;
320
+ const datasource = self[datasourceLinkedElementSymbol];
321
+ if (!datasource) {
322
+ return;
323
+ }
324
+
325
+ element = findTargetElementFromEvent(
326
+ event,
327
+ ATTRIBUTE_ROLE,
328
+ "pagination-item",
329
+ );
330
+
331
+ if (!element) {
332
+ element = findTargetElementFromEvent(
333
+ event,
334
+ ATTRIBUTE_ROLE,
335
+ "pagination-next",
336
+ );
337
+ if (!element) {
338
+ element = findTargetElementFromEvent(
339
+ event,
340
+ ATTRIBUTE_ROLE,
341
+ "pagination-prev",
342
+ );
343
+ if (!element) {
344
+ return;
345
+ }
346
+ }
347
+ }
348
+
349
+ if (!(element instanceof HTMLElement)) {
350
+ return;
351
+ }
352
+
353
+ let page = null;
354
+
355
+ if (!element.hasAttribute("data-page-no")) {
356
+ return;
357
+ }
358
+
359
+ page = element.getAttribute("data-page-no");
360
+
361
+ if (
362
+ !page ||
363
+ page === "" ||
364
+ page === null ||
365
+ page === undefined ||
366
+ page === "undefined" ||
367
+ page === "null"
368
+ ) {
369
+ return;
370
+ }
371
+
372
+ if (typeof datasource.setParameters !== "function") {
373
+ return;
374
+ }
375
+
376
+ event.preventDefault();
377
+ datasource.setParameters({page});
378
+
379
+ if (typeof datasource.reload !== "function") {
380
+ return;
381
+ }
382
+
383
+ datasource.reload();
384
+ });
372
385
  }
373
386
 
374
387
  /**
@@ -384,53 +397,58 @@ function initEventHandler() {
384
397
  * @throws {Error} the datasource could not be initialized
385
398
  */
386
399
  function initOptionsFromArguments() {
387
- const options = {};
388
- const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
389
- if (selector) {
390
- options.datasource = { selector: selector };
391
- }
400
+ const options = {};
401
+ const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
402
+ if (selector) {
403
+ options.datasource = {selector: selector};
404
+ }
392
405
 
393
- return options;
406
+ return options;
394
407
  }
395
408
 
396
409
  /**
397
410
  * @private
398
411
  */
399
412
  function handleDataSourceChanges() {
400
- let pagination;
401
-
402
- if (!this[datasourceLinkedElementSymbol]) {
403
- return;
404
- }
405
-
406
- const mapping = this.getOption("mapping");
407
- for (const key in mapping) {
408
- const path = mapping[key];
409
-
410
- let value;
411
- try {
412
- value = new Pathfinder(this[datasourceLinkedElementSymbol].data).getVia(
413
- path,
414
- );
415
- this.setOption(key, value);
416
- } catch (e) {
417
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
418
- }
419
- }
420
-
421
- pagination = buildPagination.call(
422
- this,
423
- this.getOption("currentPage"),
424
- this.getOption("pages"),
425
- );
426
-
427
- if (this?.[sizeDataSymbol]?.showNumbers !== true) {
428
- pagination.items = [];
429
- }
430
-
431
- getWindow().requestAnimationFrame(() => {
432
- this.setOption("pagination", pagination);
433
- });
413
+ let pagination;
414
+
415
+ if (!this[datasourceLinkedElementSymbol]) {
416
+ return;
417
+ }
418
+
419
+ const mapping = this.getOption("mapping");
420
+ const pf = new Pathfinder(this[datasourceLinkedElementSymbol].data);
421
+
422
+ for (const key in mapping) {
423
+ const path = mapping[key];
424
+
425
+ if (pf.exists(path)) {
426
+ const value = pf.getVia(
427
+ path,
428
+ );
429
+ this.setOption(key, value);
430
+ }
431
+
432
+ const o = this[datasourceLinkedElementSymbol].getOption(path);
433
+ if (o !== undefined && o !== null) {
434
+ this.setOption(key, o);
435
+ }
436
+
437
+ }
438
+
439
+ pagination = buildPagination.call(
440
+ this,
441
+ this.getOption("currentPage"),
442
+ this.getOption("pages"),
443
+ );
444
+
445
+ if (this?.[sizeDataSymbol]?.showNumbers !== true) {
446
+ pagination.items = [];
447
+ }
448
+
449
+ getWindow().requestAnimationFrame(() => {
450
+ this.setOption("pagination", pagination);
451
+ });
434
452
  }
435
453
 
436
454
  /**
@@ -440,88 +458,92 @@ function handleDataSourceChanges() {
440
458
  * @return {object}
441
459
  */
442
460
  function buildPagination(current, max) {
443
- let prev = current === 1 ? null : current - 1;
444
- let next = current === max ? null : current + 1;
445
- const itemList = [1];
446
-
447
- if (current > 4) itemList.push("…");
448
-
449
- const r = 2;
450
- const r1 = current - r;
451
- const r2 = current + r;
452
-
453
- for (let i = r1 > 2 ? r1 : 2; i <= Math.min(max, r2); i++) itemList.push(i);
454
-
455
- if (r2 + 1 < max) itemList.push("…");
456
- if (r2 < max) itemList.push(max);
457
-
458
- let prevClass = "";
459
-
460
- if (prev === null) {
461
- prevClass = " disabled";
462
- }
463
-
464
- let nextClass = "";
465
- if (next === null) {
466
- nextClass = " disabled";
467
- }
468
-
469
- const items = itemList.map((item) => {
470
- const p = `${item}`;
471
- const c = `${current}`;
472
-
473
- const obj = {
474
- pageNo: item, // as integer
475
- page: p, // as string
476
- current: p === c,
477
- class: (p === c ? "current" : "").trim(),
478
- };
479
-
480
- if (p === "…") {
481
- obj.class += " disabled".trim();
482
- }
483
-
484
- const formatter = new Formatter(obj);
485
-
486
- obj.description = formatter.format(this.getOption("labels.description"));
487
- obj.label = formatter.format(this.getOption("labels.page"));
488
- obj.href =
489
- p === "…"
490
- ? "#"
491
- : p === c
492
- ? "#"
493
- : p === "1"
494
- ? "#"
495
- : `#${formatter.format(this.getOption("href"))}`;
496
- return obj;
497
- });
498
-
499
- const nextNo = next;
500
- next = `${next}`;
501
-
502
- const nextHref =
503
- next === "null"
504
- ? "#"
505
- : `#${new Formatter({ page: next }).format(this.getOption("href"))}`;
506
- const prevNo = prev;
507
- prev = `${prev}`;
508
- const prevHref =
509
- prev === "null"
510
- ? "#"
511
- : `#${new Formatter({ page: prev }).format(this.getOption("href"))}`;
512
-
513
- return {
514
- current,
515
- nextNo,
516
- next,
517
- nextClass,
518
- nextHref,
519
- prevNo,
520
- prev,
521
- prevClass,
522
- prevHref,
523
- items,
524
- };
461
+
462
+ current = parseInt(current, 10);
463
+ max = parseInt(max, 10);
464
+
465
+ let prev = current === 1 ? null : current - 1;
466
+ let next = current === max ? null : current + 1;
467
+ const itemList = [1];
468
+
469
+ if (current > 4) itemList.push("…");
470
+
471
+ const r = 2;
472
+ const r1 = current - r;
473
+ const r2 = current + r;
474
+
475
+ for (let i = r1 > 2 ? r1 : 2; i <= Math.min(max, r2); i++) itemList.push(i);
476
+
477
+ if (r2 + 1 < max) itemList.push("…");
478
+ if (r2 < max) itemList.push(max);
479
+
480
+ let prevClass = "";
481
+
482
+ if (prev === null) {
483
+ prevClass = " disabled";
484
+ }
485
+
486
+ let nextClass = "";
487
+ if (next === null) {
488
+ nextClass = " disabled";
489
+ }
490
+
491
+ const items = itemList.map((item) => {
492
+ const p = `${item}`;
493
+ const c = `${current}`;
494
+
495
+ const obj = {
496
+ pageNo: item, // as integer
497
+ page: p, // as string
498
+ current: p === c,
499
+ class: (p === c ? "current" : "").trim(),
500
+ };
501
+
502
+ if (p === "…") {
503
+ obj.class += " disabled".trim();
504
+ }
505
+
506
+ const formatter = new Formatter(obj);
507
+
508
+ obj.description = formatter.format(this.getOption("labels.description"));
509
+ obj.label = formatter.format(this.getOption("labels.page"));
510
+ obj.href =
511
+ p === ""
512
+ ? "#"
513
+ : p === c
514
+ ? "#"
515
+ : p === "1"
516
+ ? "#"
517
+ : `#${formatter.format(this.getOption("href"))}`;
518
+ return obj;
519
+ });
520
+
521
+ const nextNo = next;
522
+ next = `${next}`;
523
+
524
+ const nextHref =
525
+ next === "null"
526
+ ? "#"
527
+ : `#${new Formatter({page: next}).format(this.getOption("href"))}`;
528
+ const prevNo = prev;
529
+ prev = `${prev}`;
530
+ const prevHref =
531
+ prev === "null"
532
+ ? "#"
533
+ : `#${new Formatter({page: prev}).format(this.getOption("href"))}`;
534
+
535
+ return {
536
+ current,
537
+ nextNo,
538
+ next,
539
+ nextClass,
540
+ nextHref,
541
+ prevNo,
542
+ prev,
543
+ prevClass,
544
+ prevHref,
545
+ items,
546
+ };
525
547
  }
526
548
 
527
549
  /**
@@ -529,8 +551,8 @@ function buildPagination(current, max) {
529
551
  * @return {string}
530
552
  */
531
553
  function getTemplate() {
532
- // language=HTML
533
- return `
554
+ // language=HTML
555
+ return `
534
556
  <template id="items">
535
557
  <li><a data-monster-attributes="class path:items.class,
536
558
  href path:items.href,