@schukai/monster 4.107.1 → 4.109.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.
- package/CHANGELOG.md +25 -0
- package/package.json +1 -1
- package/source/components/datatable/filter/select-operator.mjs +525 -0
- package/source/components/datatable/pagination.mjs +39 -4
- package/source/components/datatable/style/filter-select.pcss +2 -1
- package/source/components/form/select.mjs +8 -1
- package/source/components/form/style/input-group.pcss +4 -3
- package/source/components/form/stylesheet/input-group.mjs +1 -1
- package/source/monster.mjs +2 -1
- package/source/types/version.mjs +1 -1
- package/test/cases/components/layout/tabs.mjs +22 -15
- package/test/cases/monster.mjs +1 -1
- package/test/web/import.js +1 -0
- package/test/web/test.html +2 -2
- package/test/web/tests.js +864 -222
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
## [4.109.0] - 2026-01-28
|
|
6
|
+
|
|
7
|
+
### Add Features
|
|
8
|
+
|
|
9
|
+
- Add double-click handling to pagination navigation
|
|
10
|
+
- Improve pagination visibility for zero results
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
- webtests
|
|
14
|
+
- update webstest
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## [4.108.0] - 2026-01-26
|
|
19
|
+
|
|
20
|
+
### Add Features
|
|
21
|
+
|
|
22
|
+
- Improve localization support and clean up code [#378](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/378)
|
|
23
|
+
- Add monster-filter-select-operator component and related files [#378](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/378)
|
|
24
|
+
### Bug Fixes
|
|
25
|
+
|
|
26
|
+
- update project
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
5
30
|
## [4.107.1] - 2026-01-25
|
|
6
31
|
|
|
7
32
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.
|
|
1
|
+
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.109.0"}
|
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright © Volker Schukai and all contributing authors, {{copyRightYear}}. All rights reserved.
|
|
3
|
+
* Node module: @schukai/monster
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
|
|
6
|
+
* The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
|
|
7
|
+
*
|
|
8
|
+
* For those who do not wish to adhere to the AGPLv3, a commercial license is available.
|
|
9
|
+
* Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
|
|
10
|
+
* For more information about purchasing a commercial license, please contact Volker Schukai.
|
|
11
|
+
*
|
|
12
|
+
* SPDX-License-Identifier: AGPL-3.0
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { instanceSymbol } from "../../../constants.mjs";
|
|
16
|
+
import {
|
|
17
|
+
assembleMethodSymbol,
|
|
18
|
+
registerCustomElement,
|
|
19
|
+
} from "../../../dom/customelement.mjs";
|
|
20
|
+
import { CustomControl } from "../../../dom/customcontrol.mjs";
|
|
21
|
+
import { fireCustomEvent, fireEvent } from "../../../dom/events.mjs";
|
|
22
|
+
import { getLocaleOfDocument } from "../../../dom/locale.mjs";
|
|
23
|
+
import { isArray, isObject, isString } from "../../../types/is.mjs";
|
|
24
|
+
import { Observer } from "../../../types/observer.mjs";
|
|
25
|
+
import { FilterControlsDefaultsStyleSheet } from "../stylesheet/filter-controls-defaults.mjs";
|
|
26
|
+
import { FilterStyleSheet } from "../stylesheet/filter.mjs";
|
|
27
|
+
import "../../form/input-group.mjs";
|
|
28
|
+
import "./select.mjs";
|
|
29
|
+
|
|
30
|
+
export { SelectOperator };
|
|
31
|
+
|
|
32
|
+
const operatorElementSymbol = Symbol("operatorElement");
|
|
33
|
+
const selectElementSymbol = Symbol("selectElement");
|
|
34
|
+
const lastSnapshotSymbol = Symbol("lastSnapshot");
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The FilterSelectOperator component combines a select-operator with a multi select.
|
|
38
|
+
*
|
|
39
|
+
* @fragments /fragments/components/datatable/filter/select-operator
|
|
40
|
+
*
|
|
41
|
+
* @example /examples/components/datatable/filter-controls Filter controls
|
|
42
|
+
*
|
|
43
|
+
* @copyright Volker Schukai
|
|
44
|
+
* @summary The FilterSelectOperator component combines operator and select input.
|
|
45
|
+
*/
|
|
46
|
+
class SelectOperator extends CustomControl {
|
|
47
|
+
constructor() {
|
|
48
|
+
super();
|
|
49
|
+
initOptionObserver.call(this);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* This method is called by the `instanceof` operator.
|
|
53
|
+
* @return {symbol}
|
|
54
|
+
*/
|
|
55
|
+
static get [instanceSymbol]() {
|
|
56
|
+
return Symbol.for(
|
|
57
|
+
"@schukai/monster/components/filter/select-operator@@instance",
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* To set the options via the HTML tag, the attribute `data-monster-options` must be used.
|
|
63
|
+
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
|
|
64
|
+
*
|
|
65
|
+
* @property {Object} templates Template definitions
|
|
66
|
+
* @property {string} templates.main Main template
|
|
67
|
+
* @property {Object} labels Text labels
|
|
68
|
+
* @property {Array<Object>} operators Operator definitions `{ value, label }`
|
|
69
|
+
* @property {Object} select Options forwarded to the nested `monster-filter-select`
|
|
70
|
+
*/
|
|
71
|
+
get defaults() {
|
|
72
|
+
const labels = getTranslations();
|
|
73
|
+
return Object.assign({}, super.defaults, {
|
|
74
|
+
templates: {
|
|
75
|
+
main: getTemplate(),
|
|
76
|
+
},
|
|
77
|
+
labels,
|
|
78
|
+
operators: getDefaultOperators(labels),
|
|
79
|
+
select: {},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @return {string}
|
|
85
|
+
*/
|
|
86
|
+
static getTag() {
|
|
87
|
+
return "monster-filter-select-operator";
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @return {SelectOperator}
|
|
92
|
+
*/
|
|
93
|
+
[assembleMethodSymbol]() {
|
|
94
|
+
super[assembleMethodSymbol]();
|
|
95
|
+
initControlReferences.call(this);
|
|
96
|
+
updateOperators.call(this);
|
|
97
|
+
applySelectOptions.call(this);
|
|
98
|
+
initEventHandlers.call(this);
|
|
99
|
+
syncFormValue.call(this);
|
|
100
|
+
return this;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* @return {CSSStyleSheet[]}
|
|
105
|
+
*/
|
|
106
|
+
static getCSSStyleSheet() {
|
|
107
|
+
return [FilterControlsDefaultsStyleSheet, FilterStyleSheet];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Ensure option updates are forwarded to the nested select.
|
|
112
|
+
*
|
|
113
|
+
* @param {string|object} options
|
|
114
|
+
* @return {SelectOperator}
|
|
115
|
+
*/
|
|
116
|
+
setOptions(options) {
|
|
117
|
+
super.setOptions(options);
|
|
118
|
+
if (this[operatorElementSymbol]) {
|
|
119
|
+
updateOperators.call(this);
|
|
120
|
+
}
|
|
121
|
+
applySelectOptions.call(this);
|
|
122
|
+
return this;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @return {string}
|
|
127
|
+
*/
|
|
128
|
+
get operator() {
|
|
129
|
+
return this[operatorElementSymbol]?.value || "";
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @param {string} value
|
|
134
|
+
*/
|
|
135
|
+
set operator(value) {
|
|
136
|
+
if (isString(value) && this[operatorElementSymbol]) {
|
|
137
|
+
this[operatorElementSymbol].value = value;
|
|
138
|
+
syncFormValue.call(this);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* @return {string[]}
|
|
144
|
+
*/
|
|
145
|
+
get selection() {
|
|
146
|
+
return normalizeSelection(this[selectElementSymbol]?.value);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @param {string[]|string} value
|
|
151
|
+
*/
|
|
152
|
+
set selection(value) {
|
|
153
|
+
if (this[selectElementSymbol]) {
|
|
154
|
+
this[selectElementSymbol].value = value;
|
|
155
|
+
syncFormValue.call(this);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @return {string}
|
|
161
|
+
*/
|
|
162
|
+
get value() {
|
|
163
|
+
return buildValue.call(this);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* @param {string|Array|Object} value
|
|
168
|
+
*/
|
|
169
|
+
set value(value) {
|
|
170
|
+
applyValue.call(this, value);
|
|
171
|
+
syncFormValue.call(this);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function initOptionObserver() {
|
|
176
|
+
this[lastSnapshotSymbol] = "";
|
|
177
|
+
this.attachObserver(
|
|
178
|
+
new Observer(() => {
|
|
179
|
+
const snapshot = JSON.stringify({
|
|
180
|
+
operators: this.getOption("operators"),
|
|
181
|
+
labels: this.getOption("labels"),
|
|
182
|
+
select: this.getOption("select"),
|
|
183
|
+
});
|
|
184
|
+
if (snapshot !== this[lastSnapshotSymbol]) {
|
|
185
|
+
this[lastSnapshotSymbol] = snapshot;
|
|
186
|
+
if (this[operatorElementSymbol]) {
|
|
187
|
+
updateOperators.call(this);
|
|
188
|
+
}
|
|
189
|
+
applySelectOptions.call(this);
|
|
190
|
+
}
|
|
191
|
+
}),
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function initControlReferences() {
|
|
196
|
+
if (!this.shadowRoot) {
|
|
197
|
+
throw new Error("no shadow-root is defined");
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
this[operatorElementSymbol] = this.shadowRoot.querySelector(
|
|
201
|
+
"[data-monster-role=operator]",
|
|
202
|
+
);
|
|
203
|
+
this[selectElementSymbol] = this.shadowRoot.querySelector(
|
|
204
|
+
"[data-monster-role=select]",
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function updateOperators() {
|
|
209
|
+
const operators = this.getOption("operators");
|
|
210
|
+
const list =
|
|
211
|
+
isArray(operators) && operators.length
|
|
212
|
+
? operators
|
|
213
|
+
: getDefaultOperators(this.getOption("labels"));
|
|
214
|
+
const currentValue = this[operatorElementSymbol].value;
|
|
215
|
+
|
|
216
|
+
this[operatorElementSymbol].innerHTML = "";
|
|
217
|
+
for (const operator of list) {
|
|
218
|
+
const option = document.createElement("option");
|
|
219
|
+
option.value = operator.value;
|
|
220
|
+
option.textContent = operator.label;
|
|
221
|
+
this[operatorElementSymbol].append(option);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (currentValue) {
|
|
225
|
+
this[operatorElementSymbol].value = currentValue;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function applySelectOptions() {
|
|
230
|
+
const selectOptions = this.getOption("select");
|
|
231
|
+
if (!selectOptions || !this[selectElementSymbol]) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
this[selectElementSymbol].setOptions(selectOptions);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function initEventHandlers() {
|
|
238
|
+
this[operatorElementSymbol].addEventListener("change", () => {
|
|
239
|
+
syncFormValue.call(this, true);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
this[selectElementSymbol].addEventListener("monster-selected", () => {
|
|
243
|
+
syncFormValue.call(this, true);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
this[selectElementSymbol].addEventListener("change", () => {
|
|
247
|
+
syncFormValue.call(this, true);
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function syncFormValue(fire) {
|
|
252
|
+
const value = this.value;
|
|
253
|
+
try {
|
|
254
|
+
this.setFormValue(value);
|
|
255
|
+
} catch (error) {
|
|
256
|
+
// ignore form association errors
|
|
257
|
+
}
|
|
258
|
+
if (fire) {
|
|
259
|
+
fireCustomEvent(this, "monster-change", { value });
|
|
260
|
+
fireEvent(this, "change");
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function buildValue() {
|
|
265
|
+
const operator = this.operator || "";
|
|
266
|
+
const selection = normalizeSelection(this[selectElementSymbol]?.value);
|
|
267
|
+
if (!selection.length || !operator) {
|
|
268
|
+
return "";
|
|
269
|
+
}
|
|
270
|
+
return `${operator}:${selection.join(",")}`;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function applyValue(value) {
|
|
274
|
+
if (!this[operatorElementSymbol] || !this[selectElementSymbol]) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (isObject(value)) {
|
|
279
|
+
const operator = value.operator || value.op;
|
|
280
|
+
const selection = value.selection || value.values || value.value;
|
|
281
|
+
if (isString(operator)) {
|
|
282
|
+
this[operatorElementSymbol].value = operator;
|
|
283
|
+
}
|
|
284
|
+
if (selection !== undefined) {
|
|
285
|
+
this[selectElementSymbol].value = selection;
|
|
286
|
+
}
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (isArray(value)) {
|
|
291
|
+
this[selectElementSymbol].value = value;
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (isString(value)) {
|
|
296
|
+
const parsed = parseValue(value);
|
|
297
|
+
if (parsed.operator) {
|
|
298
|
+
this[operatorElementSymbol].value = parsed.operator;
|
|
299
|
+
}
|
|
300
|
+
this[selectElementSymbol].value = parsed.selection;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function parseValue(value) {
|
|
305
|
+
const raw = `${value ?? ""}`.trim();
|
|
306
|
+
if (!raw) {
|
|
307
|
+
return { operator: "", selection: [] };
|
|
308
|
+
}
|
|
309
|
+
const index = raw.indexOf(":");
|
|
310
|
+
if (index === -1) {
|
|
311
|
+
return { operator: "", selection: raw.split(",") };
|
|
312
|
+
}
|
|
313
|
+
const operator = raw.slice(0, index).trim();
|
|
314
|
+
const selection = raw
|
|
315
|
+
.slice(index + 1)
|
|
316
|
+
.split(",")
|
|
317
|
+
.map((item) => item.trim());
|
|
318
|
+
return { operator, selection: selection.filter(Boolean) };
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function normalizeSelection(value) {
|
|
322
|
+
if (value === null || value === undefined || value === "") {
|
|
323
|
+
return [];
|
|
324
|
+
}
|
|
325
|
+
if (isArray(value)) {
|
|
326
|
+
return value.map((item) => String(item));
|
|
327
|
+
}
|
|
328
|
+
return [String(value)];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function getDefaultOperators(labels) {
|
|
332
|
+
return [
|
|
333
|
+
{ value: "one-of", label: labels.oneOf },
|
|
334
|
+
{ value: "all-of", label: labels.allOf },
|
|
335
|
+
{ value: "none-of", label: labels.noneOf },
|
|
336
|
+
{ value: "any-of", label: labels.anyOf },
|
|
337
|
+
];
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function getTranslations() {
|
|
341
|
+
const locale = getLocaleOfDocument();
|
|
342
|
+
switch (locale.language) {
|
|
343
|
+
case "de":
|
|
344
|
+
return {
|
|
345
|
+
oneOf: "eins von",
|
|
346
|
+
allOf: "alle",
|
|
347
|
+
noneOf: "keins von",
|
|
348
|
+
anyOf: "oder",
|
|
349
|
+
};
|
|
350
|
+
case "es":
|
|
351
|
+
return {
|
|
352
|
+
oneOf: "uno de",
|
|
353
|
+
allOf: "todos",
|
|
354
|
+
noneOf: "ninguno de",
|
|
355
|
+
anyOf: "o",
|
|
356
|
+
};
|
|
357
|
+
case "zh":
|
|
358
|
+
return {
|
|
359
|
+
oneOf: "其中之一",
|
|
360
|
+
allOf: "全部",
|
|
361
|
+
noneOf: "都不",
|
|
362
|
+
anyOf: "或",
|
|
363
|
+
};
|
|
364
|
+
case "hi":
|
|
365
|
+
return {
|
|
366
|
+
oneOf: "इनमें से एक",
|
|
367
|
+
allOf: "सभी",
|
|
368
|
+
noneOf: "कोई नहीं",
|
|
369
|
+
anyOf: "या",
|
|
370
|
+
};
|
|
371
|
+
case "bn":
|
|
372
|
+
return {
|
|
373
|
+
oneOf: "একটি",
|
|
374
|
+
allOf: "সব",
|
|
375
|
+
noneOf: "কোনোটিই নয়",
|
|
376
|
+
anyOf: "বা",
|
|
377
|
+
};
|
|
378
|
+
case "pt":
|
|
379
|
+
return {
|
|
380
|
+
oneOf: "um de",
|
|
381
|
+
allOf: "todos",
|
|
382
|
+
noneOf: "nenhum de",
|
|
383
|
+
anyOf: "ou",
|
|
384
|
+
};
|
|
385
|
+
case "ru":
|
|
386
|
+
return {
|
|
387
|
+
oneOf: "один из",
|
|
388
|
+
allOf: "все",
|
|
389
|
+
noneOf: "ни один из",
|
|
390
|
+
anyOf: "или",
|
|
391
|
+
};
|
|
392
|
+
case "ja":
|
|
393
|
+
return {
|
|
394
|
+
oneOf: "いずれか",
|
|
395
|
+
allOf: "すべて",
|
|
396
|
+
noneOf: "どれでもない",
|
|
397
|
+
anyOf: "または",
|
|
398
|
+
};
|
|
399
|
+
case "pa":
|
|
400
|
+
return {
|
|
401
|
+
oneOf: "ਇਨ੍ਹਾਂ ਵਿੱਚੋਂ ਇੱਕ",
|
|
402
|
+
allOf: "ਸਾਰੇ",
|
|
403
|
+
noneOf: "ਕੋਈ ਨਹੀਂ",
|
|
404
|
+
anyOf: "ਜਾਂ",
|
|
405
|
+
};
|
|
406
|
+
case "mr":
|
|
407
|
+
return {
|
|
408
|
+
oneOf: "यापैकी एक",
|
|
409
|
+
allOf: "सर्व",
|
|
410
|
+
noneOf: "कोणतेही नाही",
|
|
411
|
+
anyOf: "किंवा",
|
|
412
|
+
};
|
|
413
|
+
case "fr":
|
|
414
|
+
return {
|
|
415
|
+
oneOf: "un de",
|
|
416
|
+
allOf: "tous",
|
|
417
|
+
noneOf: "aucun de",
|
|
418
|
+
anyOf: "ou",
|
|
419
|
+
};
|
|
420
|
+
case "it":
|
|
421
|
+
return {
|
|
422
|
+
oneOf: "uno di",
|
|
423
|
+
allOf: "tutti",
|
|
424
|
+
noneOf: "nessuno di",
|
|
425
|
+
anyOf: "o",
|
|
426
|
+
};
|
|
427
|
+
case "nl":
|
|
428
|
+
return {
|
|
429
|
+
oneOf: "een van",
|
|
430
|
+
allOf: "alle",
|
|
431
|
+
noneOf: "geen van",
|
|
432
|
+
anyOf: "of",
|
|
433
|
+
};
|
|
434
|
+
case "sv":
|
|
435
|
+
return {
|
|
436
|
+
oneOf: "en av",
|
|
437
|
+
allOf: "alla",
|
|
438
|
+
noneOf: "ingen av",
|
|
439
|
+
anyOf: "eller",
|
|
440
|
+
};
|
|
441
|
+
case "pl":
|
|
442
|
+
return {
|
|
443
|
+
oneOf: "jeden z",
|
|
444
|
+
allOf: "wszystkie",
|
|
445
|
+
noneOf: "żaden z",
|
|
446
|
+
anyOf: "lub",
|
|
447
|
+
};
|
|
448
|
+
case "da":
|
|
449
|
+
return {
|
|
450
|
+
oneOf: "en af",
|
|
451
|
+
allOf: "alle",
|
|
452
|
+
noneOf: "ingen af",
|
|
453
|
+
anyOf: "eller",
|
|
454
|
+
};
|
|
455
|
+
case "fi":
|
|
456
|
+
return {
|
|
457
|
+
oneOf: "yksi",
|
|
458
|
+
allOf: "kaikki",
|
|
459
|
+
noneOf: "ei mikään",
|
|
460
|
+
anyOf: "tai",
|
|
461
|
+
};
|
|
462
|
+
case "no":
|
|
463
|
+
return {
|
|
464
|
+
oneOf: "en av",
|
|
465
|
+
allOf: "alle",
|
|
466
|
+
noneOf: "ingen av",
|
|
467
|
+
anyOf: "eller",
|
|
468
|
+
};
|
|
469
|
+
case "cs":
|
|
470
|
+
return {
|
|
471
|
+
oneOf: "jeden z",
|
|
472
|
+
allOf: "všechny",
|
|
473
|
+
noneOf: "žádný z",
|
|
474
|
+
anyOf: "nebo",
|
|
475
|
+
};
|
|
476
|
+
default:
|
|
477
|
+
case "en":
|
|
478
|
+
return {
|
|
479
|
+
oneOf: "one of",
|
|
480
|
+
allOf: "all of",
|
|
481
|
+
noneOf: "none of",
|
|
482
|
+
anyOf: "any of",
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function getTemplate() {
|
|
488
|
+
// language=HTML
|
|
489
|
+
return `
|
|
490
|
+
<style>
|
|
491
|
+
monster-filter-select::part(control) {
|
|
492
|
+
border: none;
|
|
493
|
+
box-shadow: none;
|
|
494
|
+
}
|
|
495
|
+
monster-input-group {
|
|
496
|
+
width: 100%;
|
|
497
|
+
height: 100%;
|
|
498
|
+
align-self: stretch;
|
|
499
|
+
}
|
|
500
|
+
monster-input-group::part(control) {
|
|
501
|
+
align-items: stretch;
|
|
502
|
+
}
|
|
503
|
+
monster-input-group::part(prefix) {
|
|
504
|
+
align-self: stretch;
|
|
505
|
+
}
|
|
506
|
+
[data-monster-role="operator"] {
|
|
507
|
+
height: -webkit-fill-available;
|
|
508
|
+
height: -moz-available;
|
|
509
|
+
height: fill-available;
|
|
510
|
+
}
|
|
511
|
+
</style>
|
|
512
|
+
<div data-monster-role="control" part="control">
|
|
513
|
+
<slot></slot>
|
|
514
|
+
<monster-input-group>
|
|
515
|
+
<select slot="prefix" data-monster-role="operator" name="operator"></select>
|
|
516
|
+
<monster-filter-select
|
|
517
|
+
data-monster-role="select"
|
|
518
|
+
style="flex: 1 1 auto; min-width: 0; width: 1%; height: -webkit-fill-available; height: -moz-available; height: fill-available; align-self: stretch;"
|
|
519
|
+
></monster-filter-select>
|
|
520
|
+
</monster-input-group>
|
|
521
|
+
</div>
|
|
522
|
+
`;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
registerCustomElement(SelectOperator);
|
|
@@ -89,6 +89,10 @@ const layoutApplySymbol = Symbol("layoutApply");
|
|
|
89
89
|
*/
|
|
90
90
|
const labelStateSymbol = Symbol("labelState");
|
|
91
91
|
const layoutModeSymbol = Symbol("layoutMode");
|
|
92
|
+
const lastNavClickTimeSymbol = Symbol("lastNavClickTime");
|
|
93
|
+
const lastNavClickTargetSymbol = Symbol("lastNavClickTarget");
|
|
94
|
+
|
|
95
|
+
const minNavDoubleClickDelayMs = 200;
|
|
92
96
|
|
|
93
97
|
const compactPrevIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><path d="M8 0a8 8 0 1 0 0 16A8 8 0 0 0 8 0m3.5 7.5a.5.5 0 0 1 0 1H5.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L5.707 7.5z"/></svg>`;
|
|
94
98
|
const compactNextIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><path d="M8 0a8 8 0 1 1 0 16A8 8 0 0 1 8 0M4.5 7.5a.5.5 0 0 0 0 1h5.793l-2.147 2.146a.5.5 0 0 0 .708.708l3-3a.5.5 0 0 0 0-.708l-3-3a.5.5 0 1 0-.708.708L10.293 7.5z"/></svg>`;
|
|
@@ -507,10 +511,22 @@ function initEventHandler() {
|
|
|
507
511
|
const self = this;
|
|
508
512
|
|
|
509
513
|
self[paginationElementSymbol].addEventListener("click", function (event) {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
+
const prevTarget = findTargetElementFromEvent(
|
|
515
|
+
event,
|
|
516
|
+
ATTRIBUTE_ROLE,
|
|
517
|
+
"pagination-prev",
|
|
518
|
+
);
|
|
519
|
+
const nextTarget = findTargetElementFromEvent(
|
|
520
|
+
event,
|
|
521
|
+
ATTRIBUTE_ROLE,
|
|
522
|
+
"pagination-next",
|
|
523
|
+
);
|
|
524
|
+
const itemTarget = findTargetElementFromEvent(
|
|
525
|
+
event,
|
|
526
|
+
ATTRIBUTE_ROLE,
|
|
527
|
+
"pagination-item",
|
|
528
|
+
);
|
|
529
|
+
const element = itemTarget || prevTarget || nextTarget;
|
|
514
530
|
|
|
515
531
|
if (
|
|
516
532
|
!(element instanceof HTMLElement) ||
|
|
@@ -519,6 +535,14 @@ function initEventHandler() {
|
|
|
519
535
|
return;
|
|
520
536
|
}
|
|
521
537
|
|
|
538
|
+
if (
|
|
539
|
+
(event.detail === 1 || event.detail === 0) &&
|
|
540
|
+
(prevTarget || nextTarget)
|
|
541
|
+
) {
|
|
542
|
+
self[lastNavClickTimeSymbol] = event.timeStamp;
|
|
543
|
+
self[lastNavClickTargetSymbol] = prevTarget ? "prev" : "next";
|
|
544
|
+
}
|
|
545
|
+
|
|
522
546
|
const page = element.getAttribute("data-page-no");
|
|
523
547
|
|
|
524
548
|
if (!page || page === "…" || page === "null" || page === "undefined") {
|
|
@@ -558,6 +582,17 @@ function initEventHandler() {
|
|
|
558
582
|
|
|
559
583
|
event.preventDefault();
|
|
560
584
|
|
|
585
|
+
const lastTarget = self[lastNavClickTargetSymbol];
|
|
586
|
+
const lastTime = self[lastNavClickTimeSymbol];
|
|
587
|
+
const currentTarget = prevTarget ? "prev" : "next";
|
|
588
|
+
if (
|
|
589
|
+
lastTarget !== currentTarget ||
|
|
590
|
+
!Number.isFinite(lastTime) ||
|
|
591
|
+
event.timeStamp - lastTime < minNavDoubleClickDelayMs
|
|
592
|
+
) {
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
|
|
561
596
|
const maxPage = parseInt(self.getOption("pages"), 10);
|
|
562
597
|
if (!Number.isFinite(maxPage) || maxPage <= 0) {
|
|
563
598
|
return;
|
|
@@ -942,6 +942,13 @@ function processAndApplyPaginationData(data) {
|
|
|
942
942
|
|
|
943
943
|
this.setOption("total", total);
|
|
944
944
|
|
|
945
|
+
if (total === 0) {
|
|
946
|
+
this[paginationElementSymbol].style.display = "none";
|
|
947
|
+
this[paginationElementSymbol].setOption("pages", null);
|
|
948
|
+
this[paginationElementSymbol].setOption("currentPage", null);
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
|
|
945
952
|
if (
|
|
946
953
|
isInteger(currentPage) &&
|
|
947
954
|
currentPage > 0 &&
|
|
@@ -4106,7 +4113,7 @@ function getTemplate() {
|
|
|
4106
4113
|
</div>
|
|
4107
4114
|
|
|
4108
4115
|
<div data-monster-role="popper" part="popper" tabindex="-1" class="monster-color-primary-1">
|
|
4109
|
-
<div class="option-filter-control" role="search">
|
|
4116
|
+
<div class="option-filter-control" role="search" part="popper-filter-control">
|
|
4110
4117
|
<input type="text" role="searchbox"
|
|
4111
4118
|
data-monster-attributes="placeholder path:placeholder.filter"
|
|
4112
4119
|
part="popper-filter" name="popper-filter"
|
|
@@ -25,10 +25,12 @@
|
|
|
25
25
|
|
|
26
26
|
position: relative;
|
|
27
27
|
|
|
28
|
-
::slotted(
|
|
28
|
+
::slotted(input),
|
|
29
|
+
::slotted(select),
|
|
30
|
+
::slotted(textarea),
|
|
31
|
+
::slotted(button) {
|
|
29
32
|
height: auto;
|
|
30
33
|
border: none;
|
|
31
|
-
--monster-border-width: 0;
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
::slotted(svg) {
|
|
@@ -50,4 +52,3 @@
|
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
}
|
|
53
|
-
|