@schukai/monster 4.136.19 → 4.136.21
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/package.json +1 -1
- package/source/components/datatable/pagination.mjs +43 -19
- package/source/components/form/select.mjs +308 -67
- package/source/components/form/util/floating-ui.mjs +44 -17
- package/test/cases/components/datatable/pagination.mjs +59 -0
- package/test/cases/components/form/floating-ui.mjs +73 -0
- package/test/cases/components/form/popper-button.mjs +40 -0
- package/test/cases/components/form/select.mjs +203 -1
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6"},"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.136.
|
|
1
|
+
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6"},"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.136.21"}
|
|
@@ -205,10 +205,26 @@ class Pagination extends CustomElement {
|
|
|
205
205
|
return;
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
+
const previousCurrentPage = Number.parseInt(
|
|
209
|
+
this.getOption("currentPage"),
|
|
210
|
+
10,
|
|
211
|
+
);
|
|
212
|
+
const previousTotalPages = Number.parseInt(this.getOption("pages"), 10);
|
|
213
|
+
const stateUnchanged =
|
|
214
|
+
Number.isFinite(previousCurrentPage) &&
|
|
215
|
+
Number.isFinite(previousTotalPages) &&
|
|
216
|
+
previousCurrentPage === currentPage &&
|
|
217
|
+
previousTotalPages === totalPages;
|
|
218
|
+
|
|
208
219
|
// 1. Update the component's internal options with the new values.
|
|
209
220
|
this.setOption("currentPage", currentPage);
|
|
210
221
|
this.setOption("pages", totalPages);
|
|
211
222
|
|
|
223
|
+
if (stateUnchanged) {
|
|
224
|
+
this.refreshLayout({ schedule: true });
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
212
228
|
// 2. Call the existing buildPagination function to recalculate the links.
|
|
213
229
|
const pagination = buildPagination.call(
|
|
214
230
|
this,
|
|
@@ -227,20 +243,35 @@ class Pagination extends CustomElement {
|
|
|
227
243
|
// 4. Set the 'pagination' option, which will trigger the component to re-render.
|
|
228
244
|
this.setOption("pagination", pagination);
|
|
229
245
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
246
|
+
this.refreshLayout({ schedule: true });
|
|
247
|
+
|
|
248
|
+
syncPaginationStateToDom.call(this, pagination);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
refreshLayout({ schedule = false } = {}) {
|
|
252
|
+
if (schedule === true) {
|
|
253
|
+
if (isAdaptivePagination.call(this)) {
|
|
254
|
+
schedulePaginationLayoutUpdate.call(this);
|
|
255
|
+
} else {
|
|
256
|
+
const list = this.shadowRoot?.querySelector(".pagination-list");
|
|
257
|
+
if (list) {
|
|
258
|
+
list.setAttribute("data-monster-adaptive-ready", "true");
|
|
259
|
+
}
|
|
240
260
|
}
|
|
261
|
+
return this;
|
|
241
262
|
}
|
|
242
263
|
|
|
243
|
-
|
|
264
|
+
if (isAdaptivePagination.call(this)) {
|
|
265
|
+
applyPaginationLayout.call(this);
|
|
266
|
+
return this;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const list = this.shadowRoot?.querySelector(".pagination-list");
|
|
270
|
+
if (list) {
|
|
271
|
+
list.setAttribute("data-monster-adaptive-ready", "true");
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return this;
|
|
244
275
|
}
|
|
245
276
|
/**
|
|
246
277
|
*
|
|
@@ -677,14 +708,7 @@ function handleDataSourceChanges() {
|
|
|
677
708
|
|
|
678
709
|
this.setOption("pagination", pagination);
|
|
679
710
|
|
|
680
|
-
|
|
681
|
-
schedulePaginationLayoutUpdate.call(this);
|
|
682
|
-
} else {
|
|
683
|
-
const list = this.shadowRoot?.querySelector(".pagination-list");
|
|
684
|
-
if (list) {
|
|
685
|
-
list.setAttribute("data-monster-adaptive-ready", "true");
|
|
686
|
-
}
|
|
687
|
-
}
|
|
711
|
+
this.refreshLayout({ schedule: isAdaptivePagination.call(this) });
|
|
688
712
|
}
|
|
689
713
|
|
|
690
714
|
/**
|
|
@@ -138,6 +138,12 @@ const clearOptionEventHandler = Symbol("clearOptionEventHandler");
|
|
|
138
138
|
*/
|
|
139
139
|
const resizeObserverSymbol = Symbol("resizeObserver");
|
|
140
140
|
const resizeObserverFrameSymbol = Symbol("resizeObserverFrame");
|
|
141
|
+
const layoutCycleFrameSymbol = Symbol("layoutCycleFrame");
|
|
142
|
+
const layoutCycleTokenSymbol = Symbol("layoutCycleToken");
|
|
143
|
+
const layoutCycleModeSymbol = Symbol("layoutCycleMode");
|
|
144
|
+
const layoutCyclePendingFlagsSymbol = Symbol("layoutCyclePendingFlags");
|
|
145
|
+
const layoutCyclePendingPrioritySymbol = Symbol("layoutCyclePendingPriority");
|
|
146
|
+
const layoutCycleRunningSymbol = Symbol("layoutCycleRunning");
|
|
141
147
|
const visualViewportResizeHandlerSymbol = Symbol("visualViewportResizeHandler");
|
|
142
148
|
const visualViewportScrollHandlerSymbol = Symbol("visualViewportScrollHandler");
|
|
143
149
|
const visibilityChangeHandlerSymbol = Symbol("visibilityChangeHandler");
|
|
@@ -307,6 +313,19 @@ const lookupInProgressSymbol = Symbol("lookupInProgress");
|
|
|
307
313
|
const unresolvedSelectionValuesSymbol = Symbol("unresolvedSelectionValues");
|
|
308
314
|
const fetchRequestVersionSymbol = Symbol("fetchRequestVersion");
|
|
309
315
|
const remoteInfoRequestSymbol = Symbol("remoteInfoRequest");
|
|
316
|
+
const remoteInfoStableMessageSymbol = Symbol("remoteInfoStableMessage");
|
|
317
|
+
|
|
318
|
+
const SELECT_LAYOUT_PRIORITY_PASSIVE = 1;
|
|
319
|
+
const SELECT_LAYOUT_PRIORITY_INTERACTIVE = 2;
|
|
320
|
+
const SELECT_LAYOUT_PRIORITY_CRITICAL = 3;
|
|
321
|
+
|
|
322
|
+
const SELECT_LAYOUT_REASON_OPTION_STATE = 1 << 0;
|
|
323
|
+
const SELECT_LAYOUT_REASON_PAGINATION = 1 << 1;
|
|
324
|
+
const SELECT_LAYOUT_REASON_POSITION = 1 << 2;
|
|
325
|
+
const SELECT_LAYOUT_REASON_ALL =
|
|
326
|
+
SELECT_LAYOUT_REASON_OPTION_STATE |
|
|
327
|
+
SELECT_LAYOUT_REASON_PAGINATION |
|
|
328
|
+
SELECT_LAYOUT_REASON_POSITION;
|
|
310
329
|
|
|
311
330
|
/**
|
|
312
331
|
* @private
|
|
@@ -709,19 +728,21 @@ class Select extends CustomControl {
|
|
|
709
728
|
}
|
|
710
729
|
|
|
711
730
|
this.setOption("messages.selected", "");
|
|
712
|
-
|
|
731
|
+
setRemoteInfoText.call(this, "");
|
|
713
732
|
this.setOption("messages.summary", "");
|
|
714
733
|
this.setOption("total", null);
|
|
715
734
|
resetPaginationState.call(this);
|
|
716
735
|
|
|
717
|
-
|
|
736
|
+
resetErrorAttribute(this);
|
|
718
737
|
|
|
719
|
-
|
|
738
|
+
this[lazyLoadDoneSymbol] = false;
|
|
720
739
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
740
|
+
scheduleSelectLayoutCycle.call(
|
|
741
|
+
this,
|
|
742
|
+
SELECT_LAYOUT_PRIORITY_CRITICAL,
|
|
743
|
+
SELECT_LAYOUT_REASON_ALL,
|
|
744
|
+
);
|
|
745
|
+
})
|
|
725
746
|
.catch((e) => {
|
|
726
747
|
addErrorAttribute(this, e);
|
|
727
748
|
});
|
|
@@ -1102,6 +1123,44 @@ function processAndApplyRemoteInfoTotal(data) {
|
|
|
1102
1123
|
}
|
|
1103
1124
|
}
|
|
1104
1125
|
|
|
1126
|
+
/**
|
|
1127
|
+
* @private
|
|
1128
|
+
* @param {string|null|undefined} message
|
|
1129
|
+
* @param {object} [options]
|
|
1130
|
+
* @param {boolean} [options.reserveSpace=false]
|
|
1131
|
+
* @returns {void}
|
|
1132
|
+
*/
|
|
1133
|
+
function setRemoteInfoText(message, { reserveSpace = false } = {}) {
|
|
1134
|
+
const normalizedMessage =
|
|
1135
|
+
message === undefined || message === null ? "" : `${message}`;
|
|
1136
|
+
const previousStableMessage =
|
|
1137
|
+
typeof this[remoteInfoStableMessageSymbol] === "string"
|
|
1138
|
+
? this[remoteInfoStableMessageSymbol]
|
|
1139
|
+
: "";
|
|
1140
|
+
const renderedMessage =
|
|
1141
|
+
reserveSpace === true &&
|
|
1142
|
+
normalizedMessage === "" &&
|
|
1143
|
+
previousStableMessage !== ""
|
|
1144
|
+
? previousStableMessage
|
|
1145
|
+
: normalizedMessage;
|
|
1146
|
+
|
|
1147
|
+
this.setOption("messages.total", renderedMessage);
|
|
1148
|
+
|
|
1149
|
+
if (normalizedMessage !== "") {
|
|
1150
|
+
this[remoteInfoStableMessageSymbol] = normalizedMessage;
|
|
1151
|
+
} else if (reserveSpace !== true) {
|
|
1152
|
+
this[remoteInfoStableMessageSymbol] = "";
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
if (this[remoteInfoElementSymbol] instanceof HTMLElement) {
|
|
1156
|
+
if (reserveSpace === true && renderedMessage !== "") {
|
|
1157
|
+
this[remoteInfoElementSymbol].style.visibility = "hidden";
|
|
1158
|
+
} else {
|
|
1159
|
+
this[remoteInfoElementSymbol].style.removeProperty("visibility");
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1105
1164
|
/**
|
|
1106
1165
|
* @private
|
|
1107
1166
|
* @returns {number}
|
|
@@ -1964,7 +2023,9 @@ function fetchIt(url, controlOptions) {
|
|
|
1964
2023
|
classes.add("d-none");
|
|
1965
2024
|
this.setOption("classes.noOptions", classes.toString());
|
|
1966
2025
|
this.setOption("messages.emptyOptions", "");
|
|
1967
|
-
|
|
2026
|
+
setRemoteInfoText.call(this, "", {
|
|
2027
|
+
reserveSpace: true,
|
|
2028
|
+
});
|
|
1968
2029
|
}
|
|
1969
2030
|
|
|
1970
2031
|
new Processing(10, () => {
|
|
@@ -2158,6 +2219,7 @@ function disconnectResizeObserver() {
|
|
|
2158
2219
|
this[resizeObserverSymbol].disconnect();
|
|
2159
2220
|
}
|
|
2160
2221
|
cancelScheduledResizeObserverPopperUpdate.call(this);
|
|
2222
|
+
cancelScheduledSelectLayoutCycle.call(this);
|
|
2161
2223
|
|
|
2162
2224
|
const viewport = getGlobal().visualViewport;
|
|
2163
2225
|
if (
|
|
@@ -2217,7 +2279,11 @@ function scheduleResizeObserverPopperUpdate() {
|
|
|
2217
2279
|
|
|
2218
2280
|
this[resizeObserverFrameSymbol] = schedule(() => {
|
|
2219
2281
|
delete this[resizeObserverFrameSymbol];
|
|
2220
|
-
|
|
2282
|
+
scheduleSelectLayoutCycle.call(
|
|
2283
|
+
this,
|
|
2284
|
+
SELECT_LAYOUT_PRIORITY_CRITICAL,
|
|
2285
|
+
SELECT_LAYOUT_REASON_ALL,
|
|
2286
|
+
);
|
|
2221
2287
|
});
|
|
2222
2288
|
}
|
|
2223
2289
|
|
|
@@ -2236,6 +2302,155 @@ function cancelScheduledResizeObserverPopperUpdate() {
|
|
|
2236
2302
|
delete this[resizeObserverFrameSymbol];
|
|
2237
2303
|
}
|
|
2238
2304
|
|
|
2305
|
+
function applySelectLayoutState(layoutReasons = 0) {
|
|
2306
|
+
if (layoutReasons & SELECT_LAYOUT_REASON_OPTION_STATE) {
|
|
2307
|
+
checkOptionState.call(this);
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
calcAndSetOptionsDimension.call(this);
|
|
2311
|
+
|
|
2312
|
+
if (layoutReasons & SELECT_LAYOUT_REASON_PAGINATION) {
|
|
2313
|
+
refreshSelectPaginationLayout.call(this);
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2317
|
+
function performSelectLayoutCycle(layoutReasons = SELECT_LAYOUT_REASON_ALL) {
|
|
2318
|
+
if (!isPositionedPopperOpen(this[popperElementSymbol])) {
|
|
2319
|
+
return Promise.resolve();
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
if (this.getOption("disabled", false) === true) {
|
|
2323
|
+
return Promise.resolve();
|
|
2324
|
+
}
|
|
2325
|
+
|
|
2326
|
+
return new Processing(() => {
|
|
2327
|
+
applySelectLayoutState.call(this, layoutReasons);
|
|
2328
|
+
if (layoutReasons & SELECT_LAYOUT_REASON_POSITION) {
|
|
2329
|
+
return positionPopper.call(
|
|
2330
|
+
this,
|
|
2331
|
+
this[controlElementSymbol],
|
|
2332
|
+
this[popperElementSymbol],
|
|
2333
|
+
getSelectPopperPositionOptions.call(this),
|
|
2334
|
+
);
|
|
2335
|
+
}
|
|
2336
|
+
}).run();
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
function cancelScheduledSelectLayoutCycle() {
|
|
2340
|
+
const globalObject = getGlobal();
|
|
2341
|
+
const frameId = this[layoutCycleFrameSymbol];
|
|
2342
|
+
if (typeof frameId === "number") {
|
|
2343
|
+
if (globalObject?.cancelAnimationFrame instanceof Function) {
|
|
2344
|
+
globalObject.cancelAnimationFrame(frameId);
|
|
2345
|
+
} else {
|
|
2346
|
+
globalObject.clearTimeout(frameId);
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
delete this[layoutCycleFrameSymbol];
|
|
2351
|
+
this[layoutCycleTokenSymbol] = (this[layoutCycleTokenSymbol] || 0) + 1;
|
|
2352
|
+
delete this[layoutCycleModeSymbol];
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
function flushScheduledSelectLayoutCycle() {
|
|
2356
|
+
if (this[layoutCycleRunningSymbol] === true) {
|
|
2357
|
+
return;
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
const layoutReasons =
|
|
2361
|
+
this[layoutCyclePendingFlagsSymbol] || SELECT_LAYOUT_REASON_ALL;
|
|
2362
|
+
const layoutPriority =
|
|
2363
|
+
this[layoutCyclePendingPrioritySymbol] || SELECT_LAYOUT_PRIORITY_INTERACTIVE;
|
|
2364
|
+
|
|
2365
|
+
delete this[layoutCyclePendingFlagsSymbol];
|
|
2366
|
+
delete this[layoutCyclePendingPrioritySymbol];
|
|
2367
|
+
|
|
2368
|
+
this[layoutCycleRunningSymbol] = true;
|
|
2369
|
+
performSelectLayoutCycle
|
|
2370
|
+
.call(this, layoutReasons)
|
|
2371
|
+
.catch((e) => {
|
|
2372
|
+
addErrorAttribute(this, e);
|
|
2373
|
+
})
|
|
2374
|
+
.finally(() => {
|
|
2375
|
+
delete this[layoutCycleRunningSymbol];
|
|
2376
|
+
if (this[layoutCyclePendingFlagsSymbol]) {
|
|
2377
|
+
scheduleSelectLayoutCycle.call(
|
|
2378
|
+
this,
|
|
2379
|
+
layoutPriority,
|
|
2380
|
+
this[layoutCyclePendingFlagsSymbol],
|
|
2381
|
+
);
|
|
2382
|
+
}
|
|
2383
|
+
});
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
function scheduleSelectLayoutCycle(
|
|
2387
|
+
layoutPriority = SELECT_LAYOUT_PRIORITY_INTERACTIVE,
|
|
2388
|
+
layoutReasons = SELECT_LAYOUT_REASON_ALL,
|
|
2389
|
+
) {
|
|
2390
|
+
this[layoutCyclePendingFlagsSymbol] =
|
|
2391
|
+
(this[layoutCyclePendingFlagsSymbol] || 0) | layoutReasons;
|
|
2392
|
+
this[layoutCyclePendingPrioritySymbol] = Math.max(
|
|
2393
|
+
this[layoutCyclePendingPrioritySymbol] || 0,
|
|
2394
|
+
layoutPriority,
|
|
2395
|
+
);
|
|
2396
|
+
|
|
2397
|
+
if (this[layoutCycleRunningSymbol] === true) {
|
|
2398
|
+
return;
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
const pendingPriority = this[layoutCyclePendingPrioritySymbol];
|
|
2402
|
+
const currentMode = this[layoutCycleModeSymbol];
|
|
2403
|
+
if (
|
|
2404
|
+
currentMode === "microtask" ||
|
|
2405
|
+
(currentMode === "frame" &&
|
|
2406
|
+
pendingPriority !== SELECT_LAYOUT_PRIORITY_CRITICAL)
|
|
2407
|
+
) {
|
|
2408
|
+
return;
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2411
|
+
if (pendingPriority === SELECT_LAYOUT_PRIORITY_CRITICAL) {
|
|
2412
|
+
cancelScheduledSelectLayoutCycle.call(this);
|
|
2413
|
+
const token = this[layoutCycleTokenSymbol];
|
|
2414
|
+
this[layoutCycleModeSymbol] = "microtask";
|
|
2415
|
+
queueMicrotask(() => {
|
|
2416
|
+
if (
|
|
2417
|
+
this[layoutCycleModeSymbol] !== "microtask" ||
|
|
2418
|
+
this[layoutCycleTokenSymbol] !== token
|
|
2419
|
+
) {
|
|
2420
|
+
return;
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
delete this[layoutCycleModeSymbol];
|
|
2424
|
+
flushScheduledSelectLayoutCycle.call(this);
|
|
2425
|
+
});
|
|
2426
|
+
return;
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2429
|
+
const globalObject = getGlobal();
|
|
2430
|
+
const schedule =
|
|
2431
|
+
globalObject?.requestAnimationFrame instanceof Function
|
|
2432
|
+
? globalObject.requestAnimationFrame.bind(globalObject)
|
|
2433
|
+
: (callback) => {
|
|
2434
|
+
return globalObject.setTimeout(callback, 16);
|
|
2435
|
+
};
|
|
2436
|
+
|
|
2437
|
+
this[layoutCycleModeSymbol] = "frame";
|
|
2438
|
+
const token = (this[layoutCycleTokenSymbol] || 0) + 1;
|
|
2439
|
+
this[layoutCycleTokenSymbol] = token;
|
|
2440
|
+
this[layoutCycleFrameSymbol] = schedule(() => {
|
|
2441
|
+
delete this[layoutCycleFrameSymbol];
|
|
2442
|
+
if (
|
|
2443
|
+
this[layoutCycleModeSymbol] !== "frame" ||
|
|
2444
|
+
this[layoutCycleTokenSymbol] !== token
|
|
2445
|
+
) {
|
|
2446
|
+
return;
|
|
2447
|
+
}
|
|
2448
|
+
|
|
2449
|
+
delete this[layoutCycleModeSymbol];
|
|
2450
|
+
flushScheduledSelectLayoutCycle.call(this);
|
|
2451
|
+
});
|
|
2452
|
+
}
|
|
2453
|
+
|
|
2239
2454
|
/**
|
|
2240
2455
|
* @private
|
|
2241
2456
|
* @returns {string}
|
|
@@ -2327,6 +2542,27 @@ function buildSelectionLabel(value) {
|
|
|
2327
2542
|
return map.get(key);
|
|
2328
2543
|
}
|
|
2329
2544
|
|
|
2545
|
+
const options = this.getOption("options");
|
|
2546
|
+
if (isArray(options)) {
|
|
2547
|
+
for (const option of options) {
|
|
2548
|
+
if (!isObject(option) || option.value === undefined) {
|
|
2549
|
+
continue;
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
const optionKey = strict
|
|
2553
|
+
? option.value
|
|
2554
|
+
: getSelectionStateKey.call(this, option.value);
|
|
2555
|
+
if (optionKey !== key) {
|
|
2556
|
+
continue;
|
|
2557
|
+
}
|
|
2558
|
+
|
|
2559
|
+
if (clearUnresolvedSelectionValue.call(this, value)) {
|
|
2560
|
+
this[lookupCacheSymbol].delete(getSelectionCacheKey.call(this, value));
|
|
2561
|
+
}
|
|
2562
|
+
return option.label;
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2330
2566
|
const cacheKey = getSelectionCacheKey.call(this, value);
|
|
2331
2567
|
if (this[lookupCacheSymbol].has(cacheKey)) {
|
|
2332
2568
|
return this[lookupCacheSymbol].get(cacheKey);
|
|
@@ -2773,19 +3009,21 @@ function setTotalText() {
|
|
|
2773
3009
|
}
|
|
2774
3010
|
|
|
2775
3011
|
if (this[isLoadingSymbol] === true) {
|
|
2776
|
-
|
|
3012
|
+
setRemoteInfoText.call(this, "", {
|
|
3013
|
+
reserveSpace: true,
|
|
3014
|
+
});
|
|
2777
3015
|
return;
|
|
2778
3016
|
}
|
|
2779
3017
|
|
|
2780
3018
|
const count = this.getOption("options").length;
|
|
2781
3019
|
if (count === 0) {
|
|
2782
|
-
|
|
3020
|
+
setRemoteInfoText.call(this, "");
|
|
2783
3021
|
return;
|
|
2784
3022
|
}
|
|
2785
3023
|
|
|
2786
3024
|
const total = Number.parseInt(this.getOption("total"));
|
|
2787
3025
|
if (Number.isNaN(total)) {
|
|
2788
|
-
|
|
3026
|
+
setRemoteInfoText.call(this, "");
|
|
2789
3027
|
return;
|
|
2790
3028
|
}
|
|
2791
3029
|
|
|
@@ -2793,7 +3031,7 @@ function setTotalText() {
|
|
|
2793
3031
|
|
|
2794
3032
|
const diff = total - count;
|
|
2795
3033
|
if (diff < 0) {
|
|
2796
|
-
|
|
3034
|
+
setRemoteInfoText.call(this, "");
|
|
2797
3035
|
return;
|
|
2798
3036
|
}
|
|
2799
3037
|
const text = translations.getPluralRuleText("total", diff, "");
|
|
@@ -2801,7 +3039,7 @@ function setTotalText() {
|
|
|
2801
3039
|
count: String(diff),
|
|
2802
3040
|
}).format(text);
|
|
2803
3041
|
|
|
2804
|
-
|
|
3042
|
+
setRemoteInfoText.call(this, selectedText);
|
|
2805
3043
|
}
|
|
2806
3044
|
|
|
2807
3045
|
/**
|
|
@@ -2959,6 +3197,7 @@ function calcAndSetOptionsDimension() {
|
|
|
2959
3197
|
this[popperElementSymbol].dataset.monsterPreferredWidth = `${Math.ceil(
|
|
2960
3198
|
widthConstraints.preferredWidth,
|
|
2961
3199
|
)}`;
|
|
3200
|
+
this[popperElementSymbol].dataset.monsterWidthBehavior = "preferred";
|
|
2962
3201
|
if (
|
|
2963
3202
|
Number.isFinite(widthConstraints.maxWidth) &&
|
|
2964
3203
|
widthConstraints.maxWidth > 0
|
|
@@ -2973,8 +3212,12 @@ function calcAndSetOptionsDimension() {
|
|
|
2973
3212
|
delete this[popperElementSymbol].dataset.monsterPreferredMaxWidth;
|
|
2974
3213
|
this[popperElementSymbol].style.removeProperty("maxWidth");
|
|
2975
3214
|
}
|
|
2976
|
-
this[popperElementSymbol].style.width =
|
|
2977
|
-
|
|
3215
|
+
this[popperElementSymbol].style.width = `${Math.ceil(
|
|
3216
|
+
Math.min(widthConstraints.preferredWidth, widthConstraints.maxWidth),
|
|
3217
|
+
)}px`;
|
|
3218
|
+
this[popperElementSymbol].style.minWidth = `${Math.ceil(
|
|
3219
|
+
Math.min(widthConstraints.preferredWidth, widthConstraints.maxWidth),
|
|
3220
|
+
)}px`;
|
|
2978
3221
|
this[popperElementSymbol].style.maxHeight = `${Math.ceil(
|
|
2979
3222
|
Math.min(geometry.availableHeight, SELECT_MAX_POPPER_HEIGHT),
|
|
2980
3223
|
)}px`;
|
|
@@ -3227,6 +3470,7 @@ function resetSelectPopperDimensionStyles() {
|
|
|
3227
3470
|
|
|
3228
3471
|
delete this[popperElementSymbol].dataset.monsterPreferredWidth;
|
|
3229
3472
|
delete this[popperElementSymbol].dataset.monsterPreferredMaxWidth;
|
|
3473
|
+
delete this[popperElementSymbol].dataset.monsterWidthBehavior;
|
|
3230
3474
|
this[popperElementSymbol].style.removeProperty("width");
|
|
3231
3475
|
this[popperElementSymbol].style.removeProperty("minWidth");
|
|
3232
3476
|
this[popperElementSymbol].style.removeProperty("maxWidth");
|
|
@@ -3355,12 +3599,16 @@ function filterOptions() {
|
|
|
3355
3599
|
}
|
|
3356
3600
|
}
|
|
3357
3601
|
})
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3602
|
+
.run()
|
|
3603
|
+
.then(() => {
|
|
3604
|
+
new Processing(100, () => {
|
|
3605
|
+
scheduleSelectLayoutCycle.call(
|
|
3606
|
+
this,
|
|
3607
|
+
SELECT_LAYOUT_PRIORITY_CRITICAL,
|
|
3608
|
+
SELECT_LAYOUT_REASON_PAGINATION | SELECT_LAYOUT_REASON_POSITION,
|
|
3609
|
+
);
|
|
3610
|
+
focusFilter.call(this);
|
|
3611
|
+
})
|
|
3364
3612
|
.run()
|
|
3365
3613
|
.catch((e) => {
|
|
3366
3614
|
addErrorAttribute(this, e);
|
|
@@ -4531,12 +4779,13 @@ function show() {
|
|
|
4531
4779
|
} else {
|
|
4532
4780
|
initTotal.call(self);
|
|
4533
4781
|
}
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4782
|
+
focusFilter.call(this);
|
|
4783
|
+
return performSelectLayoutCycle
|
|
4784
|
+
.call(this, SELECT_LAYOUT_REASON_ALL)
|
|
4785
|
+
.then(() => {
|
|
4786
|
+
this[popperElementSymbol].style.removeProperty("visibility");
|
|
4787
|
+
});
|
|
4788
|
+
})
|
|
4540
4789
|
.run()
|
|
4541
4790
|
.catch((e) => {
|
|
4542
4791
|
addErrorAttribute(this, e);
|
|
@@ -4621,7 +4870,9 @@ function initTotal() {
|
|
|
4621
4870
|
}
|
|
4622
4871
|
|
|
4623
4872
|
const fetchOptions = this.getOption("fetch", {});
|
|
4624
|
-
|
|
4873
|
+
setRemoteInfoText.call(this, "", {
|
|
4874
|
+
reserveSpace: true,
|
|
4875
|
+
});
|
|
4625
4876
|
|
|
4626
4877
|
const remoteInfoRequest = getGlobal()
|
|
4627
4878
|
.fetch(url, fetchOptions)
|
|
@@ -4678,7 +4929,7 @@ function resetPaginationState(clearTotalMessage = true) {
|
|
|
4678
4929
|
paginationElement.setOption("currentPage", null);
|
|
4679
4930
|
paginationElement.setOption("objectsPerPage", null);
|
|
4680
4931
|
if (clearTotalMessage === true) {
|
|
4681
|
-
|
|
4932
|
+
setRemoteInfoText.call(this, "");
|
|
4682
4933
|
}
|
|
4683
4934
|
}
|
|
4684
4935
|
|
|
@@ -4689,13 +4940,21 @@ function clearOptionsOnError() {
|
|
|
4689
4940
|
|
|
4690
4941
|
function refreshSelectPaginationLayout() {
|
|
4691
4942
|
const paginationElement = this[paginationElementSymbol];
|
|
4692
|
-
if (!paginationElement
|
|
4943
|
+
if (!paginationElement) {
|
|
4944
|
+
return;
|
|
4945
|
+
}
|
|
4946
|
+
|
|
4947
|
+
if (typeof paginationElement.refreshLayout === "function") {
|
|
4948
|
+
paginationElement.refreshLayout();
|
|
4949
|
+
return;
|
|
4950
|
+
}
|
|
4951
|
+
|
|
4952
|
+
if (typeof paginationElement.getOption !== "function") {
|
|
4693
4953
|
return;
|
|
4694
4954
|
}
|
|
4695
4955
|
|
|
4696
4956
|
const currentPage = paginationElement.getOption("currentPage");
|
|
4697
4957
|
const totalPages = paginationElement.getOption("pages");
|
|
4698
|
-
|
|
4699
4958
|
if (!isInteger(currentPage) || !isInteger(totalPages)) {
|
|
4700
4959
|
return;
|
|
4701
4960
|
}
|
|
@@ -4953,15 +5212,17 @@ function initEventHandler() {
|
|
|
4953
5212
|
}
|
|
4954
5213
|
}
|
|
4955
5214
|
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
5215
|
+
this[debounceOptionsMutationObserverSymbol] = new DeadMansSwitch(
|
|
5216
|
+
100,
|
|
5217
|
+
() => {
|
|
5218
|
+
scheduleSelectLayoutCycle.call(
|
|
5219
|
+
self,
|
|
5220
|
+
SELECT_LAYOUT_PRIORITY_INTERACTIVE,
|
|
5221
|
+
SELECT_LAYOUT_REASON_ALL,
|
|
5222
|
+
);
|
|
5223
|
+
delete this[debounceOptionsMutationObserverSymbol];
|
|
5224
|
+
},
|
|
5225
|
+
);
|
|
4965
5226
|
};
|
|
4966
5227
|
|
|
4967
5228
|
const observer = new MutationObserver(callback);
|
|
@@ -5134,7 +5395,7 @@ function initControlReferences() {
|
|
|
5134
5395
|
`[${ATTRIBUTE_ROLE}=popper]`,
|
|
5135
5396
|
);
|
|
5136
5397
|
this[popperElementSymbol].monsterBeforeFloatingUpdate = () => {
|
|
5137
|
-
|
|
5398
|
+
applySelectLayoutState.call(this, SELECT_LAYOUT_REASON_PAGINATION);
|
|
5138
5399
|
};
|
|
5139
5400
|
this[inlineFilterElementSymbol] = this.shadowRoot.querySelector(
|
|
5140
5401
|
`[${ATTRIBUTE_ROLE}=filter][name="inline-filter"]`,
|
|
@@ -5164,31 +5425,11 @@ function initControlReferences() {
|
|
|
5164
5425
|
* @private
|
|
5165
5426
|
*/
|
|
5166
5427
|
function updatePopper() {
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
return;
|
|
5173
|
-
}
|
|
5174
|
-
|
|
5175
|
-
new Processing(() => {
|
|
5176
|
-
calcAndSetOptionsDimension.call(this);
|
|
5177
|
-
positionPopper.call(
|
|
5178
|
-
this,
|
|
5179
|
-
this[controlElementSymbol],
|
|
5180
|
-
this[popperElementSymbol],
|
|
5181
|
-
getSelectPopperPositionOptions.call(this),
|
|
5182
|
-
);
|
|
5183
|
-
requestAnimationFrame(() => {
|
|
5184
|
-
refreshSelectPaginationLayout.call(this);
|
|
5185
|
-
});
|
|
5186
|
-
})
|
|
5187
|
-
.run()
|
|
5188
|
-
.catch((e) => {
|
|
5189
|
-
addErrorAttribute(this, e);
|
|
5190
|
-
});
|
|
5191
|
-
|
|
5428
|
+
scheduleSelectLayoutCycle.call(
|
|
5429
|
+
this,
|
|
5430
|
+
SELECT_LAYOUT_PRIORITY_INTERACTIVE,
|
|
5431
|
+
SELECT_LAYOUT_REASON_ALL,
|
|
5432
|
+
);
|
|
5192
5433
|
return this;
|
|
5193
5434
|
}
|
|
5194
5435
|
|
|
@@ -41,6 +41,7 @@ const settlingFrameMap = new WeakMap();
|
|
|
41
41
|
const floatingResizeObserverMap = new WeakMap();
|
|
42
42
|
const floatingSyncCycleMap = new WeakMap();
|
|
43
43
|
const floatingAppearanceFrameMap = new WeakMap();
|
|
44
|
+
const floatingAppearanceTimeoutMap = new WeakMap();
|
|
44
45
|
|
|
45
46
|
/**
|
|
46
47
|
* @private
|
|
@@ -639,6 +640,18 @@ function syncPreferredFloatingWidth(floatingElement, maxWidth) {
|
|
|
639
640
|
if (!Number.isFinite(preferredWidth) || preferredWidth <= 0) {
|
|
640
641
|
return;
|
|
641
642
|
}
|
|
643
|
+
const widthBehavior = floatingElement.dataset.monsterWidthBehavior;
|
|
644
|
+
if (widthBehavior === "preferred") {
|
|
645
|
+
const nextFloatingWidth = clampAvailableDimension(
|
|
646
|
+
preferredWidth,
|
|
647
|
+
Number.isFinite(maxWidth) ? maxWidth : Infinity,
|
|
648
|
+
);
|
|
649
|
+
if (Number.isFinite(nextFloatingWidth) && nextFloatingWidth > 0) {
|
|
650
|
+
floatingElement.style.width = `${nextFloatingWidth}px`;
|
|
651
|
+
floatingElement.style.minWidth = `${nextFloatingWidth}px`;
|
|
652
|
+
}
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
642
655
|
|
|
643
656
|
const contentElement = getFloatingContentElement(floatingElement);
|
|
644
657
|
if (!(contentElement instanceof HTMLElement)) {
|
|
@@ -1036,6 +1049,15 @@ function scheduleFloatingAppearanceOpen(popperElement) {
|
|
|
1036
1049
|
return;
|
|
1037
1050
|
}
|
|
1038
1051
|
|
|
1052
|
+
const finishAppearanceOpen = () => {
|
|
1053
|
+
cancelFloatingAppearanceFrame(popperElement);
|
|
1054
|
+
|
|
1055
|
+
if (!isPositionedPopperOpen(popperElement)) {
|
|
1056
|
+
return;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
popperElement.dataset.monsterAppearance = "open";
|
|
1060
|
+
};
|
|
1039
1061
|
const schedule =
|
|
1040
1062
|
typeof requestAnimationFrame === "function"
|
|
1041
1063
|
? requestAnimationFrame
|
|
@@ -1043,35 +1065,40 @@ function scheduleFloatingAppearanceOpen(popperElement) {
|
|
|
1043
1065
|
return setTimeout(callback, 16);
|
|
1044
1066
|
};
|
|
1045
1067
|
const frameId = schedule(() => {
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
if (!isPositionedPopperOpen(popperElement)) {
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
popperElement.dataset.monsterAppearance = "open";
|
|
1068
|
+
finishAppearanceOpen();
|
|
1053
1069
|
});
|
|
1070
|
+
const timeoutId = setTimeout(() => {
|
|
1071
|
+
finishAppearanceOpen();
|
|
1072
|
+
}, 24);
|
|
1054
1073
|
|
|
1055
1074
|
floatingAppearanceFrameMap.set(popperElement, frameId);
|
|
1075
|
+
floatingAppearanceTimeoutMap.set(popperElement, timeoutId);
|
|
1056
1076
|
}
|
|
1057
1077
|
|
|
1058
1078
|
function cancelFloatingAppearanceFrame(popperElement) {
|
|
1059
1079
|
const frameId = floatingAppearanceFrameMap.get(popperElement);
|
|
1060
1080
|
if (
|
|
1061
|
-
frameId
|
|
1062
|
-
frameId
|
|
1063
|
-
Number.isNaN(frameId) ===
|
|
1081
|
+
frameId !== undefined &&
|
|
1082
|
+
frameId !== null &&
|
|
1083
|
+
Number.isNaN(frameId) === false
|
|
1064
1084
|
) {
|
|
1065
|
-
|
|
1085
|
+
if (typeof cancelAnimationFrame === "function") {
|
|
1086
|
+
cancelAnimationFrame(frameId);
|
|
1087
|
+
} else {
|
|
1088
|
+
clearTimeout(frameId);
|
|
1089
|
+
}
|
|
1066
1090
|
}
|
|
1091
|
+
floatingAppearanceFrameMap.delete(popperElement);
|
|
1067
1092
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1093
|
+
const timeoutId = floatingAppearanceTimeoutMap.get(popperElement);
|
|
1094
|
+
if (
|
|
1095
|
+
timeoutId !== undefined &&
|
|
1096
|
+
timeoutId !== null &&
|
|
1097
|
+
Number.isNaN(timeoutId) === false
|
|
1098
|
+
) {
|
|
1099
|
+
clearTimeout(timeoutId);
|
|
1072
1100
|
}
|
|
1073
|
-
|
|
1074
|
-
floatingAppearanceFrameMap.delete(popperElement);
|
|
1101
|
+
floatingAppearanceTimeoutMap.delete(popperElement);
|
|
1075
1102
|
}
|
|
1076
1103
|
|
|
1077
1104
|
function applyFloatingArrowStyles(arrowElement, placement, arrowData) {
|
|
@@ -7,6 +7,7 @@ let expect = chai.expect;
|
|
|
7
7
|
chai.use(chaiDom);
|
|
8
8
|
|
|
9
9
|
let Pagination;
|
|
10
|
+
let EmbeddedPagination;
|
|
10
11
|
|
|
11
12
|
describe('Pagination', function () {
|
|
12
13
|
this.timeout(10000);
|
|
@@ -15,6 +16,9 @@ describe('Pagination', function () {
|
|
|
15
16
|
initJSDOM().then(() => {
|
|
16
17
|
import("../../../../source/components/datatable/pagination.mjs").then((m) => {
|
|
17
18
|
Pagination = m['Pagination'];
|
|
19
|
+
return import("../../../../source/components/datatable/embedded-pagination.mjs");
|
|
20
|
+
}).then((m) => {
|
|
21
|
+
EmbeddedPagination = m['EmbeddedPagination'];
|
|
18
22
|
done();
|
|
19
23
|
}).catch(e => done(e));
|
|
20
24
|
});
|
|
@@ -90,10 +94,65 @@ describe('Pagination', function () {
|
|
|
90
94
|
}, 0);
|
|
91
95
|
});
|
|
92
96
|
|
|
97
|
+
it('keeps adaptive pagination visible when the same state is applied again', function (done) {
|
|
98
|
+
const mocks = document.getElementById('mocks');
|
|
99
|
+
const wrapper = document.createElement('div');
|
|
100
|
+
const control = document.createElement('monster-embedded-pagination');
|
|
101
|
+
|
|
102
|
+
wrapper.getBoundingClientRect = () => ({
|
|
103
|
+
width: 320,
|
|
104
|
+
height: 40,
|
|
105
|
+
top: 0,
|
|
106
|
+
left: 0,
|
|
107
|
+
right: 320,
|
|
108
|
+
bottom: 40,
|
|
109
|
+
x: 0,
|
|
110
|
+
y: 0
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
mocks.appendChild(wrapper);
|
|
114
|
+
wrapper.appendChild(control);
|
|
115
|
+
|
|
116
|
+
setTimeout(() => {
|
|
117
|
+
try {
|
|
118
|
+
control.setPaginationState({currentPage: 2, totalPages: 5});
|
|
119
|
+
|
|
120
|
+
setTimeout(() => {
|
|
121
|
+
try {
|
|
122
|
+
const list = control.shadowRoot.querySelector('.pagination-list');
|
|
123
|
+
expect(list).to.exist;
|
|
124
|
+
|
|
125
|
+
list.setAttribute('data-monster-adaptive-ready', 'true');
|
|
126
|
+
control.setPaginationState({currentPage: 2, totalPages: 5});
|
|
127
|
+
|
|
128
|
+
expect(list.getAttribute('data-monster-adaptive-ready')).to.equal('true');
|
|
129
|
+
|
|
130
|
+
setTimeout(() => {
|
|
131
|
+
try {
|
|
132
|
+
expect(list.getAttribute('data-monster-adaptive-ready')).to.equal('true');
|
|
133
|
+
done();
|
|
134
|
+
} catch (e) {
|
|
135
|
+
done(e);
|
|
136
|
+
}
|
|
137
|
+
}, 50);
|
|
138
|
+
} catch (e) {
|
|
139
|
+
done(e);
|
|
140
|
+
}
|
|
141
|
+
}, 0);
|
|
142
|
+
} catch (e) {
|
|
143
|
+
done(e);
|
|
144
|
+
}
|
|
145
|
+
}, 0);
|
|
146
|
+
});
|
|
147
|
+
|
|
93
148
|
describe('document.createElement', function () {
|
|
94
149
|
it('should instance of Pagination', function () {
|
|
95
150
|
expect(document.createElement('monster-pagination')).is.instanceof(Pagination);
|
|
96
151
|
});
|
|
152
|
+
|
|
153
|
+
it('should instance of EmbeddedPagination', function () {
|
|
154
|
+
expect(document.createElement('monster-embedded-pagination')).is.instanceof(EmbeddedPagination);
|
|
155
|
+
});
|
|
97
156
|
});
|
|
98
157
|
|
|
99
158
|
});
|
|
@@ -237,4 +237,77 @@ describe("form floating-ui boundary resolution", function () {
|
|
|
237
237
|
expect(options.style.height).to.equal("72px");
|
|
238
238
|
expect(options.style.maxHeight).to.equal("72px");
|
|
239
239
|
});
|
|
240
|
+
|
|
241
|
+
it("should keep a preferred-width popper stable instead of growing with content", function () {
|
|
242
|
+
const mocks = document.getElementById("mocks");
|
|
243
|
+
const popper = document.createElement("div");
|
|
244
|
+
const header = document.createElement("div");
|
|
245
|
+
const content = document.createElement("div");
|
|
246
|
+
const options = document.createElement("div");
|
|
247
|
+
|
|
248
|
+
popper.dataset.monsterPreferredWidth = "240";
|
|
249
|
+
popper.dataset.monsterWidthBehavior = "preferred";
|
|
250
|
+
popper.style.maxWidth = "600px";
|
|
251
|
+
content.setAttribute("part", "content");
|
|
252
|
+
options.style.overflowY = "auto";
|
|
253
|
+
|
|
254
|
+
Object.defineProperty(content, "scrollWidth", {
|
|
255
|
+
configurable: true,
|
|
256
|
+
value: 620,
|
|
257
|
+
});
|
|
258
|
+
Object.defineProperty(options, "scrollWidth", {
|
|
259
|
+
configurable: true,
|
|
260
|
+
value: 620,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
header.getBoundingClientRect = () => {
|
|
264
|
+
return {
|
|
265
|
+
width: 240,
|
|
266
|
+
height: 24,
|
|
267
|
+
top: 0,
|
|
268
|
+
left: 0,
|
|
269
|
+
right: 240,
|
|
270
|
+
bottom: 24,
|
|
271
|
+
x: 0,
|
|
272
|
+
y: 0,
|
|
273
|
+
};
|
|
274
|
+
};
|
|
275
|
+
content.getBoundingClientRect = () => {
|
|
276
|
+
return {
|
|
277
|
+
width: 220,
|
|
278
|
+
height: 120,
|
|
279
|
+
top: 0,
|
|
280
|
+
left: 0,
|
|
281
|
+
right: 220,
|
|
282
|
+
bottom: 120,
|
|
283
|
+
x: 0,
|
|
284
|
+
y: 0,
|
|
285
|
+
};
|
|
286
|
+
};
|
|
287
|
+
popper.getBoundingClientRect = () => {
|
|
288
|
+
return {
|
|
289
|
+
width: 240,
|
|
290
|
+
height: 160,
|
|
291
|
+
top: 0,
|
|
292
|
+
left: 0,
|
|
293
|
+
right: 240,
|
|
294
|
+
bottom: 160,
|
|
295
|
+
x: 0,
|
|
296
|
+
y: 0,
|
|
297
|
+
};
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
content.appendChild(options);
|
|
301
|
+
popper.appendChild(header);
|
|
302
|
+
popper.appendChild(content);
|
|
303
|
+
mocks.appendChild(popper);
|
|
304
|
+
|
|
305
|
+
applyAdaptiveFloatingElementSize(popper, {
|
|
306
|
+
availableWidth: 600,
|
|
307
|
+
availableHeight: 200,
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
expect(popper.style.width).to.equal("240px");
|
|
311
|
+
expect(popper.style.minWidth).to.equal("240px");
|
|
312
|
+
});
|
|
240
313
|
});
|
|
@@ -235,4 +235,44 @@ describe("PopperButton", function () {
|
|
|
235
235
|
}
|
|
236
236
|
}, 0);
|
|
237
237
|
});
|
|
238
|
+
|
|
239
|
+
it("should finish the opening appearance state when requestAnimationFrame stalls", function (done) {
|
|
240
|
+
let mocks = document.getElementById("mocks");
|
|
241
|
+
const button = document.createElement("monster-popper-button");
|
|
242
|
+
const originalRequestAnimationFrame = globalThis.requestAnimationFrame;
|
|
243
|
+
const originalCancelAnimationFrame = globalThis.cancelAnimationFrame;
|
|
244
|
+
|
|
245
|
+
globalThis.requestAnimationFrame = () => 1;
|
|
246
|
+
globalThis.cancelAnimationFrame = () => {};
|
|
247
|
+
mocks.appendChild(button);
|
|
248
|
+
|
|
249
|
+
setTimeout(() => {
|
|
250
|
+
try {
|
|
251
|
+
button.showDialog();
|
|
252
|
+
|
|
253
|
+
const popper = button.shadowRoot.querySelector(
|
|
254
|
+
'[data-monster-role="popper"]',
|
|
255
|
+
);
|
|
256
|
+
expect(popper).to.exist;
|
|
257
|
+
expect(popper.dataset.monsterAppearance).to.equal("opening");
|
|
258
|
+
|
|
259
|
+
setTimeout(() => {
|
|
260
|
+
try {
|
|
261
|
+
expect(popper.dataset.monsterAppearance).to.equal("open");
|
|
262
|
+
button.hideDialog();
|
|
263
|
+
done();
|
|
264
|
+
} catch (e) {
|
|
265
|
+
done(e);
|
|
266
|
+
} finally {
|
|
267
|
+
globalThis.requestAnimationFrame = originalRequestAnimationFrame;
|
|
268
|
+
globalThis.cancelAnimationFrame = originalCancelAnimationFrame;
|
|
269
|
+
}
|
|
270
|
+
}, 30);
|
|
271
|
+
} catch (e) {
|
|
272
|
+
globalThis.requestAnimationFrame = originalRequestAnimationFrame;
|
|
273
|
+
globalThis.cancelAnimationFrame = originalCancelAnimationFrame;
|
|
274
|
+
done(e);
|
|
275
|
+
}
|
|
276
|
+
}, 0);
|
|
277
|
+
});
|
|
238
278
|
});
|
|
@@ -47,6 +47,18 @@ function createJsonResponse(data, status = 200) {
|
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
function createDeferred() {
|
|
51
|
+
let resolve;
|
|
52
|
+
let reject;
|
|
53
|
+
|
|
54
|
+
const promise = new Promise((res, rej) => {
|
|
55
|
+
resolve = res;
|
|
56
|
+
reject = rej;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return {promise, resolve, reject};
|
|
60
|
+
}
|
|
61
|
+
|
|
50
62
|
function waitForCondition(check, {timeout = 4000, interval = 25} = {}) {
|
|
51
63
|
return new Promise((resolve, reject) => {
|
|
52
64
|
const start = Date.now();
|
|
@@ -284,7 +296,8 @@ describe('Select', function () {
|
|
|
284
296
|
shadowRoot.querySelector('[data-monster-role=container]').click();
|
|
285
297
|
setTimeout(() => {
|
|
286
298
|
try {
|
|
287
|
-
expect(popper.style.minWidth).to.equal('');
|
|
299
|
+
expect(popper.style.minWidth).to.equal('240px');
|
|
300
|
+
expect(popper.dataset.monsterWidthBehavior).to.equal('preferred');
|
|
288
301
|
expect(popper.dataset.monsterPreferredWidth).to.equal('240');
|
|
289
302
|
done();
|
|
290
303
|
} catch (e) {
|
|
@@ -1140,6 +1153,195 @@ describe('Select', function () {
|
|
|
1140
1153
|
expect(select.getOption('messages.total')).to.contain('No additional entries are available');
|
|
1141
1154
|
});
|
|
1142
1155
|
|
|
1156
|
+
it('should keep the remote-info footer height stable while a remote page request is pending', async function () {
|
|
1157
|
+
this.timeout(4000);
|
|
1158
|
+
|
|
1159
|
+
let mocks = document.getElementById('mocks');
|
|
1160
|
+
const firstRequest = createDeferred();
|
|
1161
|
+
const secondRequest = createDeferred();
|
|
1162
|
+
let requestCount = 0;
|
|
1163
|
+
|
|
1164
|
+
global['fetch'] = function () {
|
|
1165
|
+
requestCount += 1;
|
|
1166
|
+
|
|
1167
|
+
if (requestCount === 1) {
|
|
1168
|
+
return firstRequest.promise;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
if (requestCount === 2) {
|
|
1172
|
+
return secondRequest.promise;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
return Promise.reject(new Error('unexpected fetch request'));
|
|
1176
|
+
};
|
|
1177
|
+
|
|
1178
|
+
const select = document.createElement('monster-select');
|
|
1179
|
+
select.setOption('url', 'https://example.com/items?filter={filter}&page={page}');
|
|
1180
|
+
select.setOption('filter.mode', 'remote');
|
|
1181
|
+
select.setOption('filter.position', 'popper');
|
|
1182
|
+
select.setOption('mapping.selector', 'items.*');
|
|
1183
|
+
select.setOption('mapping.labelTemplate', '${name}');
|
|
1184
|
+
select.setOption('mapping.valueTemplate', '${id}');
|
|
1185
|
+
select.setOption('mapping.total', 'pagination.total');
|
|
1186
|
+
select.setOption('mapping.currentPage', 'pagination.page');
|
|
1187
|
+
select.setOption('mapping.objectsPerPage', 'pagination.perPage');
|
|
1188
|
+
mocks.appendChild(select);
|
|
1189
|
+
|
|
1190
|
+
await waitForCondition(() => {
|
|
1191
|
+
return select.shadowRoot.querySelector('[data-monster-role=container]') instanceof HTMLElement;
|
|
1192
|
+
});
|
|
1193
|
+
|
|
1194
|
+
const firstFetch = select.fetch('https://example.com/items?filter=*&page=1');
|
|
1195
|
+
firstRequest.resolve(await createJsonResponse({
|
|
1196
|
+
items: [
|
|
1197
|
+
{id: 'alpha', name: 'Alpha'}
|
|
1198
|
+
],
|
|
1199
|
+
pagination: {
|
|
1200
|
+
total: 12,
|
|
1201
|
+
page: 1,
|
|
1202
|
+
perPage: 1
|
|
1203
|
+
}
|
|
1204
|
+
}));
|
|
1205
|
+
await firstFetch;
|
|
1206
|
+
|
|
1207
|
+
await waitForCondition(() => {
|
|
1208
|
+
return select.getOption('messages.total').includes('additional entries are available');
|
|
1209
|
+
});
|
|
1210
|
+
|
|
1211
|
+
const container = select.shadowRoot.querySelector('[data-monster-role=container]');
|
|
1212
|
+
const remoteInfoElement = select.shadowRoot.querySelector('[data-monster-role=remote-info]');
|
|
1213
|
+
|
|
1214
|
+
container.click();
|
|
1215
|
+
|
|
1216
|
+
await waitForCondition(() => {
|
|
1217
|
+
return select.shadowRoot
|
|
1218
|
+
.querySelector('[data-monster-role=control]')
|
|
1219
|
+
.classList
|
|
1220
|
+
.contains('open');
|
|
1221
|
+
});
|
|
1222
|
+
|
|
1223
|
+
expect(remoteInfoElement.style.visibility).to.equal('');
|
|
1224
|
+
|
|
1225
|
+
const secondFetch = select.fetch('https://example.com/items?filter=*&page=2');
|
|
1226
|
+
|
|
1227
|
+
await waitForCondition(() => {
|
|
1228
|
+
return remoteInfoElement.style.visibility === 'hidden';
|
|
1229
|
+
});
|
|
1230
|
+
|
|
1231
|
+
expect(select.getOption('messages.total')).to.contain('additional entries are available');
|
|
1232
|
+
|
|
1233
|
+
secondRequest.resolve(await createJsonResponse({
|
|
1234
|
+
items: [
|
|
1235
|
+
{id: 'beta', name: 'Beta'}
|
|
1236
|
+
],
|
|
1237
|
+
pagination: {
|
|
1238
|
+
total: 12,
|
|
1239
|
+
page: 2,
|
|
1240
|
+
perPage: 1
|
|
1241
|
+
}
|
|
1242
|
+
}));
|
|
1243
|
+
|
|
1244
|
+
await secondFetch;
|
|
1245
|
+
|
|
1246
|
+
await waitForCondition(() => {
|
|
1247
|
+
return remoteInfoElement.style.visibility === '';
|
|
1248
|
+
});
|
|
1249
|
+
|
|
1250
|
+
expect(select.getOption('messages.total')).to.contain('additional entries are available');
|
|
1251
|
+
});
|
|
1252
|
+
|
|
1253
|
+
it('should clear preserved remote-info text after a later empty remote result settles', async function () {
|
|
1254
|
+
this.timeout(4000);
|
|
1255
|
+
|
|
1256
|
+
let mocks = document.getElementById('mocks');
|
|
1257
|
+
const firstRequest = createDeferred();
|
|
1258
|
+
const secondRequest = createDeferred();
|
|
1259
|
+
let requestCount = 0;
|
|
1260
|
+
|
|
1261
|
+
global['fetch'] = function () {
|
|
1262
|
+
requestCount += 1;
|
|
1263
|
+
|
|
1264
|
+
if (requestCount === 1) {
|
|
1265
|
+
return firstRequest.promise;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
if (requestCount === 2) {
|
|
1269
|
+
return secondRequest.promise;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
return Promise.reject(new Error('unexpected fetch request'));
|
|
1273
|
+
};
|
|
1274
|
+
|
|
1275
|
+
const select = document.createElement('monster-select');
|
|
1276
|
+
select.setOption('url', 'https://example.com/items?filter={filter}&page={page}');
|
|
1277
|
+
select.setOption('filter.mode', 'remote');
|
|
1278
|
+
select.setOption('filter.position', 'popper');
|
|
1279
|
+
select.setOption('mapping.selector', 'items.*');
|
|
1280
|
+
select.setOption('mapping.labelTemplate', '${name}');
|
|
1281
|
+
select.setOption('mapping.valueTemplate', '${id}');
|
|
1282
|
+
select.setOption('mapping.total', 'pagination.total');
|
|
1283
|
+
select.setOption('mapping.currentPage', 'pagination.page');
|
|
1284
|
+
select.setOption('mapping.objectsPerPage', 'pagination.perPage');
|
|
1285
|
+
mocks.appendChild(select);
|
|
1286
|
+
|
|
1287
|
+
await waitForCondition(() => {
|
|
1288
|
+
return select.shadowRoot.querySelector('[data-monster-role=container]') instanceof HTMLElement;
|
|
1289
|
+
});
|
|
1290
|
+
|
|
1291
|
+
const firstFetch = select.fetch('https://example.com/items?filter=*&page=1');
|
|
1292
|
+
firstRequest.resolve(await createJsonResponse({
|
|
1293
|
+
items: [
|
|
1294
|
+
{id: 'alpha', name: 'Alpha'}
|
|
1295
|
+
],
|
|
1296
|
+
pagination: {
|
|
1297
|
+
total: 12,
|
|
1298
|
+
page: 1,
|
|
1299
|
+
perPage: 1
|
|
1300
|
+
}
|
|
1301
|
+
}));
|
|
1302
|
+
await firstFetch;
|
|
1303
|
+
|
|
1304
|
+
await waitForCondition(() => {
|
|
1305
|
+
return select.getOption('messages.total').includes('additional entries are available');
|
|
1306
|
+
});
|
|
1307
|
+
|
|
1308
|
+
const container = select.shadowRoot.querySelector('[data-monster-role=container]');
|
|
1309
|
+
const remoteInfoElement = select.shadowRoot.querySelector('[data-monster-role=remote-info]');
|
|
1310
|
+
|
|
1311
|
+
container.click();
|
|
1312
|
+
|
|
1313
|
+
await waitForCondition(() => {
|
|
1314
|
+
return select.shadowRoot
|
|
1315
|
+
.querySelector('[data-monster-role=control]')
|
|
1316
|
+
.classList
|
|
1317
|
+
.contains('open');
|
|
1318
|
+
});
|
|
1319
|
+
|
|
1320
|
+
const secondFetch = select.fetch('https://example.com/items?filter=leer&page=1');
|
|
1321
|
+
|
|
1322
|
+
await waitForCondition(() => {
|
|
1323
|
+
return remoteInfoElement.style.visibility === 'hidden';
|
|
1324
|
+
});
|
|
1325
|
+
|
|
1326
|
+
secondRequest.resolve(await createJsonResponse({
|
|
1327
|
+
items: [],
|
|
1328
|
+
pagination: {
|
|
1329
|
+
total: 0,
|
|
1330
|
+
page: 1,
|
|
1331
|
+
perPage: 1
|
|
1332
|
+
}
|
|
1333
|
+
}));
|
|
1334
|
+
|
|
1335
|
+
await secondFetch;
|
|
1336
|
+
|
|
1337
|
+
await waitForCondition(() => {
|
|
1338
|
+
return select.getOption('messages.total') === '';
|
|
1339
|
+
});
|
|
1340
|
+
|
|
1341
|
+
expect(remoteInfoElement.style.visibility).to.equal('');
|
|
1342
|
+
expect(select.getOption('messages.total')).to.equal('');
|
|
1343
|
+
});
|
|
1344
|
+
|
|
1143
1345
|
it('should avoid duplicate remote-info badges for empty remote filter results', async function () {
|
|
1144
1346
|
this.timeout(4000);
|
|
1145
1347
|
|