@mono-lit/helper 0.0.8 → 0.0.10
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/dist/accordion-core-DaNyPWRr.js +277 -0
- package/dist/alert-core-DWtHbX_-.js +134 -0
- package/dist/breadcrumb-list-core-Dh68T8Cf.js +747 -0
- package/dist/{mono-button-CLkHg3WW.js → button-core-DerXg84Q.js} +3 -276
- package/dist/button-dropdown-core-DKYEOyjy.js +654 -0
- package/dist/button-utils-D5-66M02.js +63 -0
- package/dist/card-utils-l80qAmrN.js +312 -0
- package/dist/chart-core-DV7hD3ZY.js +801 -0
- package/dist/checkbox-utils-DKdrhAzF.js +337 -0
- package/dist/chip-utils-DpRrd7Zj.js +403 -0
- package/dist/{data-source-controller-C6C4ej_M.js → data-source-controller-DS_JLrmS.js} +1 -1
- package/dist/{data-source-options-fxT5QIX4.js → data-source-options-DJUNU26C.js} +6 -6
- package/dist/{data-source-read-BL266IW0.js → data-source-read-uKJpRAzx.js} +2 -2
- package/dist/date-core-CyuSyvvG.js +734 -0
- package/dist/drawer-core-DbFWvNln.js +759 -0
- package/dist/dropdown-core-BCH1pK14.js +511 -0
- package/dist/dropdown-table-core-SfHUJVFq.js +1342 -0
- package/dist/export.js +1 -1
- package/dist/{field-path-BabiMrrA.js → field-path-DK2VBWHl.js} +1 -1
- package/dist/field-tooltip.css_raw-DVblekCl.js +5 -0
- package/dist/{field-validation.css_raw-Cx6SGrfP.js → field-validation.css_raw-BU7C6173.js} +1 -170
- package/dist/file-upload-core-Cz_dBQMx.js +624 -0
- package/dist/filter-builder-core-DyWjbBP7.js +381 -0
- package/dist/{filter-builder-B6Y2mmbM.js → filter-builder-vbqIuPhX.js} +1 -1
- package/dist/{filter-eval-ChDSaAUH.js → filter-eval-CqeBnMYh.js} +1 -1
- package/dist/{filter-odata-Bi27XUpQ.js → filter-odata-GsczYKNC.js} +1 -1
- package/dist/{hydration-flush-BaE9gN3C.js → hydration-flush-Volt9X7Q.js} +2 -1071
- package/dist/index.js +11 -11
- package/dist/{index.node-CLqE8F8P.js → index.node-Csy9zrr1.js} +4 -4
- package/dist/index.node.js +11 -11
- package/dist/input-utils-BglY-k0H.js +1145 -0
- package/dist/menu-core-DkAYuCZ2.js +831 -0
- package/dist/modal-core-CSBSPN_m.js +844 -0
- package/dist/mono-button-DVvZ03P-.js +280 -0
- package/dist/{mono-button.shadow-DqZMpcqY.js → mono-button.shadow-BANxMGln.js} +6 -594
- package/dist/{mono-data-chart-NKPdAgVq.js → mono-data-chart-ChF4J9RT.js} +6 -6
- package/dist/{mono-data-dropdown-DUXo_jxd.js → mono-data-dropdown-Bgj2PDfm.js} +1 -1
- package/dist/{mono-data-grid-Bb00QM72.js → mono-data-grid-DJkp96N-.js} +346 -51
- package/dist/{mono-event-BPku9HpS.js → mono-event-CAZf0F_k.js} +14 -9
- package/dist/{mono-form-controller-BrA10erm.js → mono-form-controller-DxZLvyg6.js} +2 -1
- package/dist/mono-table-checkbox-core-BKOMx8R5.js +5288 -0
- package/dist/nav-core-B5qU2dzn.js +225 -0
- package/dist/{normalize-error-D93O4q8g.js → normalize-error-BEcd1tmS.js} +2 -2
- package/dist/otp-core-DXg3vFLh.js +758 -0
- package/dist/radio-utils-Dk9Tl1jz.js +319 -0
- package/dist/rich-text-editor-core-Ddd_QaLn.js +1280 -0
- package/dist/select-utils-BgArYHk8.js +2140 -0
- package/dist/sidebar-core-CD6txDo3.js +583 -0
- package/dist/slider-core-vcWr321-.js +1014 -0
- package/dist/src/components/dropdown-table/dropdown-table-core.d.ts +2 -2
- package/dist/src/components/dropdown-table/dropdown-table-types.d.ts +1 -1
- package/dist/src/components/dropdown-table/index.d.ts +1 -1
- package/dist/src/components/dropdown-table/index.shadow.d.ts +1 -1
- package/dist/src/components/dropdown-table/mono-data-dropdown.d.ts +1 -1
- package/dist/src/components/form/form-types.d.ts +9 -3
- package/dist/src/components/input/input-core.d.ts +1 -1
- package/dist/src/components/input/input-types.d.ts +1 -1
- package/dist/src/components/otp/otp-core.d.ts +1 -1
- package/dist/src/components/select/select-core.d.ts +1 -1
- package/dist/src/components/select/select-types.d.ts +1 -1
- package/dist/src/components/slider/slider-core.d.ts +1 -1
- package/dist/src/components/slider/slider-types.d.ts +1 -1
- package/dist/src/components/table/filter-suggestion.d.ts +171 -0
- package/dist/src/components/table/index.d.ts +5 -4
- package/dist/src/components/table/index.shadow.d.ts +5 -4
- package/dist/src/components/table/mono-data-grid.d.ts +58 -3
- package/dist/src/components/table/mono-table-empty-core.d.ts +37 -0
- package/dist/src/components/table/mono-table-search-core.d.ts +22 -3
- package/dist/src/components/table/table-types.d.ts +74 -4
- package/dist/src/components/tag-input/tag-input-core.d.ts +1 -1
- package/dist/src/components/tag-input/tag-input-types.d.ts +1 -1
- package/dist/src/components/textarea/textarea-core.d.ts +1 -1
- package/dist/src/composables/mono-event.d.ts +7 -1
- package/dist/src/entries/index.d.ts +8 -6
- package/dist/src/entries/index.node.d.ts +8 -6
- package/dist/src/search/index.d.ts +1 -1
- package/dist/src/utils/group-count.d.ts +36 -0
- package/dist/switch-utils-CTZ4id2V.js +338 -0
- package/dist/tabs-core-r5-B8k_N.js +317 -0
- package/dist/tag-input-utils-D2JA90DQ.js +3060 -0
- package/dist/textarea-utils-VU1KeXm8.js +821 -0
- package/dist/ui/accordion.js +2 -274
- package/dist/ui/alert.js +2 -131
- package/dist/ui/breadcrumb.js +4 -745
- package/dist/ui/button-dropdown.js +4 -652
- package/dist/ui/button.js +2 -63
- package/dist/ui/card.js +2 -310
- package/dist/ui/chart.js +4 -800
- package/dist/ui/checkbox.js +4 -335
- package/dist/ui/chip.js +4 -402
- package/dist/ui/date.js +3 -732
- package/dist/ui/drawer.js +3 -757
- package/dist/ui/dropdown-table.js +5 -1341
- package/dist/ui/dropdown.js +4 -509
- package/dist/ui/file-upload.js +3 -622
- package/dist/ui/filter.js +5 -380
- package/dist/ui/form.js +1 -1
- package/dist/ui/index.css +130 -5
- package/dist/ui/input.js +3 -1141
- package/dist/ui/menu.js +4 -828
- package/dist/ui/modal.js +4 -843
- package/dist/ui/nav.js +4 -223
- package/dist/ui/otp.js +4 -756
- package/dist/ui/radio.js +4 -317
- package/dist/ui/rich-text-editor.js +4 -1278
- package/dist/ui/select.js +5 -2138
- package/dist/ui/shadow/accordion.js +4 -273
- package/dist/ui/shadow/alert.js +4 -130
- package/dist/ui/shadow/breadcrumb.js +5 -744
- package/dist/ui/shadow/button-dropdown.js +6 -652
- package/dist/ui/shadow/button.js +3 -63
- package/dist/ui/shadow/card.js +4 -309
- package/dist/ui/shadow/chart.js +6 -1576
- package/dist/ui/shadow/checkbox.js +4 -334
- package/dist/ui/shadow/chip.js +4 -396
- package/dist/ui/shadow/date.js +7 -731
- package/dist/ui/shadow/drawer.js +4 -756
- package/dist/ui/shadow/dropdown-table.js +8 -1762
- package/dist/ui/shadow/dropdown.js +4 -508
- package/dist/ui/shadow/file-upload.js +4 -620
- package/dist/ui/shadow/filter.js +7 -379
- package/dist/ui/shadow/input.js +6 -1140
- package/dist/ui/shadow/menu.js +5 -828
- package/dist/ui/shadow/modal.js +6 -1063
- package/dist/ui/shadow/nav.js +5 -223
- package/dist/ui/shadow/otp.js +6 -754
- package/dist/ui/shadow/radio.js +4 -316
- package/dist/ui/shadow/rich-text-editor.js +4 -1276
- package/dist/ui/shadow/select.js +6 -2136
- package/dist/ui/shadow/sidebar.js +5 -581
- package/dist/ui/shadow/slider.js +5 -1010
- package/dist/ui/shadow/switch.js +4 -335
- package/dist/ui/shadow/table.js +10 -4501
- package/dist/ui/shadow/tabs.js +6 -315
- package/dist/ui/shadow/tag-input.js +7 -3057
- package/dist/ui/shadow/textarea.js +6 -817
- package/dist/ui/sidebar.js +3 -581
- package/dist/ui/slider.js +4 -1012
- package/dist/ui/switch.js +4 -336
- package/dist/ui/table.js +9 -4502
- package/dist/ui/tabs.js +4 -315
- package/dist/ui/tag-input.js +5 -3058
- package/dist/ui/textarea.js +4 -819
- package/dist/vue.d.ts +3 -2
- package/package.json +3 -3
- package/dist/chip-strip-bNfLn52Z.js +0 -215
- package/dist/data-source-controller-Dx6IQ2CN.js +0 -243
- package/dist/data-source-options-BM4r4PRw.js +0 -558
- package/dist/data-source-read-HyBCRg1t.js +0 -242
- package/dist/excel-BXzr3uI1.js +0 -784
- package/dist/export-ixRdCS2y.js +0 -2388
- package/dist/field-tooltip-addon-CWCp19mJ.js +0 -702
- package/dist/field-tooltip.css_raw-U5UeTa2d.js +0 -269
- package/dist/filter-builder-C0T3pMx2.js +0 -208
- package/dist/form-control-core-BbiACMtL.js +0 -226
- package/dist/icon-ClxnYhBG.js +0 -19
- package/dist/import-Dc4eXC02.js +0 -612
- package/dist/light-slots-_no0r2Z-.js +0 -246
- package/dist/markdown-uGlE_OfJ.js +0 -20191
- package/dist/mono-data-grid-Bkr-e1-i.js +0 -4043
- package/dist/normalize-error-BmLbgANw.js +0 -1048
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { n as isPath, t as getFieldValue } from "./field-path-
|
|
2
|
-
import { r as readAllRows } from "./data-source-read-
|
|
3
|
-
import { n as andPredicates, r as compileFilterPredicate, t as andFilters } from "./filter-eval-
|
|
4
|
-
import { n as describeError, o as isCanceled } from "./normalize-error-
|
|
5
|
-
import { a as resolveDataSourceOptions, d as createApplyGate, f as isRolledUp,
|
|
6
|
-
import { t as arrayToODataString } from "./filter-odata-
|
|
1
|
+
import { n as isPath, t as getFieldValue } from "./field-path-DK2VBWHl.js";
|
|
2
|
+
import { r as readAllRows } from "./data-source-read-uKJpRAzx.js";
|
|
3
|
+
import { n as andPredicates, r as compileFilterPredicate, t as andFilters } from "./filter-eval-CqeBnMYh.js";
|
|
4
|
+
import { n as describeError, o as isCanceled } from "./normalize-error-BEcd1tmS.js";
|
|
5
|
+
import { _ as monoArraySource, a as resolveDataSourceOptions, d as createApplyGate, f as isRolledUp, i as normalizeSortList, n as extraLoadOptions, o as toList, p as loadApply, r as mergeDataSourceOptions, u as summaryFilterOf } from "./data-source-options-DJUNU26C.js";
|
|
6
|
+
import { t as arrayToODataString } from "./filter-odata-GsczYKNC.js";
|
|
7
7
|
import { t as createNotifier } from "./notifier-BIrqUzRh.js";
|
|
8
8
|
|
|
9
9
|
//#region src/components/chart/chart-odata.ts
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { a as parseFieldPath, c as toODataClause, l as toODataSelector, n as isPath, o as projectFields, r as mergePatch, s as setFieldValue, t as getFieldValue } from "./field-path-
|
|
2
|
-
import { a as buildGroups, c as isGroupNode, i as searchFilterOf, o as collectGroupPaths, r as readAllRows, s as flattenLeaves } from "./data-source-read-
|
|
3
|
-
import { i as joinFilters, n as andPredicates, r as compileFilterPredicate, t as andFilters } from "./filter-eval-
|
|
4
|
-
import { A as resolveSearchEntries, C as customRemoteClause, E as hasWildcardSearch, S as customPredicate, T as hasCustomSearch, h as mergeSearchFields, j as searchEntryFor, k as plainSearchColumns, n as describeError, o as isCanceled, u as DEFAULT_SEARCH_FIELDS } from "./normalize-error-
|
|
5
|
-
import { a as resolveDataSourceOptions, c as composeSummaryApply, d as createApplyGate, f as isRolledUp,
|
|
1
|
+
import { a as parseFieldPath, c as toODataClause, l as toODataSelector, n as isPath, o as projectFields, r as mergePatch, s as setFieldValue, t as getFieldValue } from "./field-path-DK2VBWHl.js";
|
|
2
|
+
import { a as buildGroups, c as isGroupNode, i as searchFilterOf, o as collectGroupPaths, r as readAllRows, s as flattenLeaves } from "./data-source-read-uKJpRAzx.js";
|
|
3
|
+
import { i as joinFilters, n as andPredicates, r as compileFilterPredicate, t as andFilters } from "./filter-eval-CqeBnMYh.js";
|
|
4
|
+
import { A as resolveSearchEntries, C as customRemoteClause, E as hasWildcardSearch, S as customPredicate, T as hasCustomSearch, h as mergeSearchFields, j as searchEntryFor, k as plainSearchColumns, n as describeError, o as isCanceled, u as DEFAULT_SEARCH_FIELDS } from "./normalize-error-BEcd1tmS.js";
|
|
5
|
+
import { _ as monoArraySource, a as resolveDataSourceOptions, c as composeSummaryApply, d as createApplyGate, f as isRolledUp, g as storeRows, i as normalizeSortList, l as summaryAliases, n as extraLoadOptions, o as toList, p as loadApply, s as buildSummaryApply, t as dataSourceOptionsKey, u as summaryFilterOf } from "./data-source-options-DJUNU26C.js";
|
|
6
6
|
import { n as unwrapReactive } from "./reactive-Dtd-esHO.js";
|
|
7
|
-
import { t as arrayToODataString } from "./filter-odata-
|
|
7
|
+
import { t as arrayToODataString } from "./filter-odata-GsczYKNC.js";
|
|
8
8
|
import { t as createNotifier } from "./notifier-BIrqUzRh.js";
|
|
9
|
-
import { t as monoFilterBuilder } from "./filter-builder-
|
|
9
|
+
import { t as monoFilterBuilder } from "./filter-builder-vbqIuPhX.js";
|
|
10
10
|
|
|
11
11
|
//#region src/components/table/store-group-source.ts
|
|
12
12
|
/**
|
|
@@ -377,6 +377,114 @@ function inRange(d, r) {
|
|
|
377
377
|
return t >= r.from.getTime() && t < r.to.getTime();
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
+
//#endregion
|
|
381
|
+
//#region src/utils/group-count.ts
|
|
382
|
+
/**
|
|
383
|
+
* Per-value row counts for ONE field, as `{ value, count }` rows.
|
|
384
|
+
*
|
|
385
|
+
* Two consumers share this: the grid's header filter (`distinctValues`) and the
|
|
386
|
+
* table search's filter suggestion (`components/table/filter-suggestion.ts`),
|
|
387
|
+
* which asks "how many rows match this search under each OTHER value of Dept".
|
|
388
|
+
*
|
|
389
|
+
* Remote: one `$apply=filter(…)/groupby((field),aggregate($count as count))`
|
|
390
|
+
* through the store (see `data-source-apply.ts` for why it rides `urlOverride`).
|
|
391
|
+
* Array: a plain tally over the rows.
|
|
392
|
+
*/
|
|
393
|
+
/**
|
|
394
|
+
* Group-count `field` through `store` with ONE `$apply`, or `null` when that path
|
|
395
|
+
* is not available — the gate is off, a wildcard path (nothing to group by), a
|
|
396
|
+
* store that cannot carry an `$apply` (a CustomStore), a failed request (reported
|
|
397
|
+
* to the gate), or a response that is not rolled up (a server that ignored the
|
|
398
|
+
* clause). An EMPTY grouped result is a real answer and comes back as `[]`.
|
|
399
|
+
*
|
|
400
|
+
* The rows are returned in server order — the caller sorts.
|
|
401
|
+
*/
|
|
402
|
+
async function groupCountViaApply(store, field, filter, gate, options = {}) {
|
|
403
|
+
const rows = await groupCountsViaApply(store, [field], filter, gate, options);
|
|
404
|
+
return rows ? rows.map((r) => ({
|
|
405
|
+
value: r.values[field],
|
|
406
|
+
count: r.count
|
|
407
|
+
})) : null;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* {@link groupCountViaApply} over SEVERAL fields at once — one
|
|
411
|
+
* `groupby((A,B),aggregate($count as count))` request, one row per combination
|
|
412
|
+
* that exists. Same `null` contract.
|
|
413
|
+
*/
|
|
414
|
+
async function groupCountsViaApply(store, fields, filter, gate, options = {}) {
|
|
415
|
+
if (gate.skip || !fields.length) return null;
|
|
416
|
+
const selectors = [];
|
|
417
|
+
for (const field of fields) {
|
|
418
|
+
if (parseFieldPath(field).hasWildcard) return null;
|
|
419
|
+
const selector = isPath(field) ? toODataSelector(field) : field;
|
|
420
|
+
if (!selector) return null;
|
|
421
|
+
selectors.push(selector);
|
|
422
|
+
}
|
|
423
|
+
const apply = `groupby((${selectors.join(",")}),aggregate($count as count))`;
|
|
424
|
+
const odataFilter = filter != null ? arrayToODataString(filter) : "";
|
|
425
|
+
const clause = odataFilter ? `filter(${odataFilter})/${apply}` : apply;
|
|
426
|
+
const top = typeof options.top === "number" && options.top >= 0 ? options.top : void 0;
|
|
427
|
+
let rows;
|
|
428
|
+
try {
|
|
429
|
+
rows = await loadApply(store, clause, { top });
|
|
430
|
+
} catch (err) {
|
|
431
|
+
gate.reject(err);
|
|
432
|
+
return null;
|
|
433
|
+
}
|
|
434
|
+
if (!rows) return null;
|
|
435
|
+
if (!rows.length) return [];
|
|
436
|
+
const first = rows[0];
|
|
437
|
+
if (!first || typeof first !== "object" || !isCount(first.count)) return null;
|
|
438
|
+
if (!isRolledUp(rows, [...fields, "count"])) return null;
|
|
439
|
+
return rows.map((r) => ({
|
|
440
|
+
values: pickValues(r, fields),
|
|
441
|
+
count: Number(r.count) || 0
|
|
442
|
+
}));
|
|
443
|
+
}
|
|
444
|
+
/** Each field's value off a row, path-aware. */
|
|
445
|
+
function pickValues(row, fields) {
|
|
446
|
+
const out = {};
|
|
447
|
+
for (const f of fields) out[f] = isPath(f) ? getFieldValue(row, f) : row?.[f];
|
|
448
|
+
return out;
|
|
449
|
+
}
|
|
450
|
+
/** {@link countValues} over several fields: one tuple per combination, with its row count. */
|
|
451
|
+
function countTuples(rows, fields) {
|
|
452
|
+
const by = /* @__PURE__ */ new Map();
|
|
453
|
+
for (const r of rows) {
|
|
454
|
+
const values = pickValues(r, fields);
|
|
455
|
+
const key = JSON.stringify(fields.map((f) => values[f] ?? null));
|
|
456
|
+
const hit = by.get(key);
|
|
457
|
+
if (hit) hit.count++;
|
|
458
|
+
else by.set(key, {
|
|
459
|
+
values,
|
|
460
|
+
count: 1
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
return [...by.values()];
|
|
464
|
+
}
|
|
465
|
+
/** A number, or a string that is one (`"12"`). */
|
|
466
|
+
function isCount(v) {
|
|
467
|
+
if (typeof v === "number") return Number.isFinite(v);
|
|
468
|
+
return typeof v === "string" && v.trim() !== "" && Number.isFinite(Number(v));
|
|
469
|
+
}
|
|
470
|
+
/** Count occurrences of `field` across `rows` (path-aware; a wildcard path flattens). */
|
|
471
|
+
function countValues(rows, field) {
|
|
472
|
+
const counts = /* @__PURE__ */ new Map();
|
|
473
|
+
const bump = (v) => {
|
|
474
|
+
counts.set(v, (counts.get(v) ?? 0) + 1);
|
|
475
|
+
};
|
|
476
|
+
const path = isPath(field);
|
|
477
|
+
for (const r of rows) if (path) {
|
|
478
|
+
const v = getFieldValue(r, field);
|
|
479
|
+
if (Array.isArray(v)) v.forEach(bump);
|
|
480
|
+
else bump(v);
|
|
481
|
+
} else bump(r?.[field]);
|
|
482
|
+
return [...counts.entries()].map(([value, count]) => ({
|
|
483
|
+
value,
|
|
484
|
+
count
|
|
485
|
+
}));
|
|
486
|
+
}
|
|
487
|
+
|
|
380
488
|
//#endregion
|
|
381
489
|
//#region src/components/table/mono-data-grid.ts
|
|
382
490
|
function monoDataGrid(ds = null, opts = {}) {
|
|
@@ -445,6 +553,9 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
445
553
|
const chunkSize = Math.max(1, opts.chunkSize ?? 100);
|
|
446
554
|
let suppressSync = false;
|
|
447
555
|
let allRows = [];
|
|
556
|
+
let browserRows = null;
|
|
557
|
+
let browserPageIndex = 0;
|
|
558
|
+
let browserPageSize = 0;
|
|
448
559
|
let scrollMode = "off";
|
|
449
560
|
let accumulated = [];
|
|
450
561
|
let scrollNextPage = 0;
|
|
@@ -504,6 +615,9 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
504
615
|
pageSizeAll: false,
|
|
505
616
|
pageCount: 0,
|
|
506
617
|
searchTerms: [],
|
|
618
|
+
filterSuggestion: null,
|
|
619
|
+
filterSuggestions: [],
|
|
620
|
+
setFilterSuggestion,
|
|
507
621
|
sorts: [],
|
|
508
622
|
sortField: null,
|
|
509
623
|
sortOrder: null,
|
|
@@ -2148,16 +2262,21 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2148
2262
|
* column sort follows — applied to the group field itself if it is one.
|
|
2149
2263
|
*/
|
|
2150
2264
|
function effectiveSort() {
|
|
2151
|
-
const keys = ctrl.sorts.map((s) => ({
|
|
2152
|
-
|
|
2265
|
+
const keys = ctrl.sorts.filter((s) => !isBrowserSortKey(s.field)).map((s) => ({
|
|
2266
|
+
field: s.field,
|
|
2267
|
+
selector: declaredSortSelector(s.field) ?? s.field,
|
|
2153
2268
|
desc: s.order === "desc"
|
|
2154
2269
|
}));
|
|
2155
|
-
|
|
2270
|
+
const entry = (k) => ({
|
|
2271
|
+
selector: k.selector,
|
|
2272
|
+
desc: k.desc
|
|
2273
|
+
});
|
|
2274
|
+
if (!groupFields.length) return keys.length ? keys.map(entry) : null;
|
|
2156
2275
|
const list = groupFields.map((f) => ({
|
|
2157
2276
|
selector: f,
|
|
2158
|
-
desc: keys.find((k) => k.
|
|
2277
|
+
desc: keys.find((k) => k.field === f)?.desc ?? false
|
|
2159
2278
|
}));
|
|
2160
|
-
for (const k of keys) if (!groupFields.includes(k.
|
|
2279
|
+
for (const k of keys) if (!groupFields.includes(k.field)) list.push(entry(k));
|
|
2161
2280
|
return list;
|
|
2162
2281
|
}
|
|
2163
2282
|
/**
|
|
@@ -2572,6 +2691,10 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2572
2691
|
syncScroll();
|
|
2573
2692
|
return;
|
|
2574
2693
|
}
|
|
2694
|
+
if (browserRows && browserSortActive()) {
|
|
2695
|
+
syncBrowser();
|
|
2696
|
+
return;
|
|
2697
|
+
}
|
|
2575
2698
|
if (pageSizeAll) {
|
|
2576
2699
|
ctrl.grouped = false;
|
|
2577
2700
|
ctrl.items = allRows;
|
|
@@ -2735,6 +2858,11 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2735
2858
|
await loadScrollPage(true);
|
|
2736
2859
|
return;
|
|
2737
2860
|
}
|
|
2861
|
+
if (browserSortActive()) {
|
|
2862
|
+
await loadBrowserSorted();
|
|
2863
|
+
return;
|
|
2864
|
+
}
|
|
2865
|
+
browserRows = null;
|
|
2738
2866
|
if (pageSizeAll && !isGrouped()) {
|
|
2739
2867
|
await loadAllChunked();
|
|
2740
2868
|
return;
|
|
@@ -2756,6 +2884,11 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2756
2884
|
await loadScrollPage(true);
|
|
2757
2885
|
return;
|
|
2758
2886
|
}
|
|
2887
|
+
if (browserSortActive()) {
|
|
2888
|
+
await loadBrowserSorted();
|
|
2889
|
+
return;
|
|
2890
|
+
}
|
|
2891
|
+
browserRows = null;
|
|
2759
2892
|
if (pageSizeAll && !isGrouped()) {
|
|
2760
2893
|
await loadAllChunked();
|
|
2761
2894
|
return;
|
|
@@ -2792,6 +2925,11 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2792
2925
|
if (serverMode()) await fetchVisibleRows();
|
|
2793
2926
|
return;
|
|
2794
2927
|
}
|
|
2928
|
+
if (browserRows && browserSortActive()) {
|
|
2929
|
+
browserPageIndex = Math.max(0, pageIndex);
|
|
2930
|
+
syncBrowser();
|
|
2931
|
+
return;
|
|
2932
|
+
}
|
|
2795
2933
|
const s = bound;
|
|
2796
2934
|
if (!s) return;
|
|
2797
2935
|
s.pageIndex?.(Math.max(0, pageIndex));
|
|
@@ -2809,6 +2947,15 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2809
2947
|
}
|
|
2810
2948
|
const s = bound;
|
|
2811
2949
|
if (!s) return;
|
|
2950
|
+
if (browserRows && browserSortActive()) {
|
|
2951
|
+
if (!all) {
|
|
2952
|
+
browserPageSize = Math.max(1, pageSize);
|
|
2953
|
+
s.pageSize?.(browserPageSize);
|
|
2954
|
+
}
|
|
2955
|
+
browserPageIndex = 0;
|
|
2956
|
+
syncBrowser();
|
|
2957
|
+
return;
|
|
2958
|
+
}
|
|
2812
2959
|
if (all) {
|
|
2813
2960
|
await loadAllChunked();
|
|
2814
2961
|
return;
|
|
@@ -2855,6 +3002,127 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2855
3002
|
ctrl.loading = bound?.isLoading?.() ?? false;
|
|
2856
3003
|
sync();
|
|
2857
3004
|
}
|
|
3005
|
+
const BROWSER_SORT_MAX_ROWS = 5e3;
|
|
3006
|
+
/** The active sort keys when ANY of them sorts in the browser, else `null`. */
|
|
3007
|
+
function browserSortKeys() {
|
|
3008
|
+
if (!ctrl.sorts.some((s) => isBrowserSortKey(s.field))) return null;
|
|
3009
|
+
return ctrl.sorts.map((s) => {
|
|
3010
|
+
const browser = isBrowserSortKey(s.field);
|
|
3011
|
+
return {
|
|
3012
|
+
field: s.field,
|
|
3013
|
+
selector: declaredSortSelector(s.field) ?? s.field,
|
|
3014
|
+
desc: s.order === "desc",
|
|
3015
|
+
aggregate: browser ? declaredSortConfig(s.field).aggregate ?? "sum" : null
|
|
3016
|
+
};
|
|
3017
|
+
});
|
|
3018
|
+
}
|
|
3019
|
+
/** Browser sort applies: a browser-sorted column is active on a flat, paged, bound table. */
|
|
3020
|
+
function browserSortActive() {
|
|
3021
|
+
return !!bound && !isGrouped() && !serverMode() && !scrollActive() && !!browserSortKeys();
|
|
3022
|
+
}
|
|
3023
|
+
/** The smallest `maxRows` any active browser-sorted column declares (default 5000). */
|
|
3024
|
+
function browserSortCap() {
|
|
3025
|
+
const caps = ctrl.sorts.filter((s) => isBrowserSortKey(s.field)).map((s) => Number(declaredSortConfig(s.field).maxRows)).filter((n) => Number.isFinite(n) && n > 0);
|
|
3026
|
+
return caps.length ? Math.min(...caps) : BROWSER_SORT_MAX_ROWS;
|
|
3027
|
+
}
|
|
3028
|
+
/** A row's matches for `selector` reduced to one sortable value. */
|
|
3029
|
+
function browserSortValue(row, selector, aggregate) {
|
|
3030
|
+
const raw = getFieldValue(row, selector);
|
|
3031
|
+
if (!aggregate) return raw;
|
|
3032
|
+
const list = Array.isArray(raw) ? raw : raw == null ? [] : [raw];
|
|
3033
|
+
if (aggregate === "count") return list.length;
|
|
3034
|
+
const nums = list.map(Number).filter((n) => Number.isFinite(n));
|
|
3035
|
+
if (!nums.length) return aggregate === "sum" ? 0 : null;
|
|
3036
|
+
if (aggregate === "min") return Math.min(...nums);
|
|
3037
|
+
if (aggregate === "max") return Math.max(...nums);
|
|
3038
|
+
const sum = nums.reduce((a, b) => a + b, 0);
|
|
3039
|
+
return aggregate === "avg" ? sum / nums.length : sum;
|
|
3040
|
+
}
|
|
3041
|
+
/** Empties last in either direction; numbers numerically; text numeric-aware. */
|
|
3042
|
+
function compareBrowserValues(a, b) {
|
|
3043
|
+
const ea = a == null || a === "";
|
|
3044
|
+
const eb = b == null || b === "";
|
|
3045
|
+
if (ea || eb) return ea === eb ? 0 : ea ? 1 : -1;
|
|
3046
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
3047
|
+
if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();
|
|
3048
|
+
return String(a).localeCompare(String(b), void 0, { numeric: true });
|
|
3049
|
+
}
|
|
3050
|
+
/** Every matching row, sorted by the active keys (stable). */
|
|
3051
|
+
function sortBrowserRows(rows) {
|
|
3052
|
+
const keys = browserSortKeys() ?? [];
|
|
3053
|
+
const decorated = rows.map((row, i) => ({
|
|
3054
|
+
row,
|
|
3055
|
+
i,
|
|
3056
|
+
v: keys.map((k) => browserSortValue(row, k.selector, k.aggregate))
|
|
3057
|
+
}));
|
|
3058
|
+
decorated.sort((x, y) => {
|
|
3059
|
+
for (let k = 0; k < keys.length; k++) {
|
|
3060
|
+
const ex = x.v[k] == null || x.v[k] === "";
|
|
3061
|
+
const ey = y.v[k] == null || y.v[k] === "";
|
|
3062
|
+
const c = compareBrowserValues(x.v[k], y.v[k]);
|
|
3063
|
+
if (c) return ex || ey ? c : keys[k].desc ? -c : c;
|
|
3064
|
+
}
|
|
3065
|
+
return x.i - y.i;
|
|
3066
|
+
});
|
|
3067
|
+
return decorated.map((d) => d.row);
|
|
3068
|
+
}
|
|
3069
|
+
/** Too many rows to sort in the browser: drop those keys, warn, load normally. */
|
|
3070
|
+
async function refuseBrowserSort(count, cap) {
|
|
3071
|
+
const fields = ctrl.sorts.filter((s) => isBrowserSortKey(s.field)).map((s) => s.field);
|
|
3072
|
+
console.warn(`[monoDataGrid] sort: "${fields.join("\", \"")}" sorts in the browser and needs every row, but ${count} match (maxRows ${cap}) — sort cleared.`);
|
|
3073
|
+
ctrl.sorts = ctrl.sorts.filter((s) => !isBrowserSortKey(s.field));
|
|
3074
|
+
syncPrimarySort();
|
|
3075
|
+
browserRows = null;
|
|
3076
|
+
applySourceSort();
|
|
3077
|
+
notify();
|
|
3078
|
+
await load();
|
|
3079
|
+
}
|
|
3080
|
+
/** Read every matching row, sort it in memory, show the first page. */
|
|
3081
|
+
async function loadBrowserSorted() {
|
|
3082
|
+
const s = bound;
|
|
3083
|
+
if (!s) return;
|
|
3084
|
+
const cap = browserSortCap();
|
|
3085
|
+
const known = s.totalCount?.();
|
|
3086
|
+
if (typeof known === "number" && known > cap) {
|
|
3087
|
+
await refuseBrowserSort(known, cap);
|
|
3088
|
+
return;
|
|
3089
|
+
}
|
|
3090
|
+
if (!browserPageSize) browserPageSize = Math.max(1, s.pageSize?.() || ctrl.pageSize || 20);
|
|
3091
|
+
ctrl.loading = true;
|
|
3092
|
+
notify();
|
|
3093
|
+
let rows = [];
|
|
3094
|
+
try {
|
|
3095
|
+
await runLoad(async () => {
|
|
3096
|
+
rows = await readAllFromSource();
|
|
3097
|
+
});
|
|
3098
|
+
} finally {
|
|
3099
|
+
ctrl.loading = false;
|
|
3100
|
+
}
|
|
3101
|
+
if (rows.length > cap) {
|
|
3102
|
+
await refuseBrowserSort(rows.length, cap);
|
|
3103
|
+
return;
|
|
3104
|
+
}
|
|
3105
|
+
browserRows = sortBrowserRows(rows);
|
|
3106
|
+
browserPageIndex = 0;
|
|
3107
|
+
sync();
|
|
3108
|
+
recomputeSummaries();
|
|
3109
|
+
}
|
|
3110
|
+
/** Map the in-memory sorted rows (current page, or all) onto `ctrl`. */
|
|
3111
|
+
function syncBrowser() {
|
|
3112
|
+
const rows = browserRows ?? [];
|
|
3113
|
+
const size = pageSizeAll ? Math.max(1, rows.length) : Math.max(1, browserPageSize);
|
|
3114
|
+
const pageCount = Math.max(1, Math.ceil(rows.length / size));
|
|
3115
|
+
browserPageIndex = Math.min(Math.max(0, browserPageIndex), pageCount - 1);
|
|
3116
|
+
const start = browserPageIndex * size;
|
|
3117
|
+
ctrl.grouped = false;
|
|
3118
|
+
ctrl.items = rows.slice(start, start + size);
|
|
3119
|
+
ctrl.pageIndex = browserPageIndex;
|
|
3120
|
+
ctrl.pageSize = size;
|
|
3121
|
+
ctrl.pageSizeAll = pageSizeAll;
|
|
3122
|
+
ctrl.totalCount = rows.length;
|
|
3123
|
+
ctrl.pageCount = pageCount;
|
|
3124
|
+
render();
|
|
3125
|
+
}
|
|
2858
3126
|
/** Scroll modes only apply to a flat (ungrouped, non-server) grid. */
|
|
2859
3127
|
function scrollActive() {
|
|
2860
3128
|
return scrollMode !== "off" && !isGrouped() && !serverMode();
|
|
@@ -3192,8 +3460,30 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
3192
3460
|
}
|
|
3193
3461
|
await setSearchTerms(ctrl.searchTerms);
|
|
3194
3462
|
}
|
|
3463
|
+
/** What identifies an offer for the change check — a re-published identical list is a no-op. */
|
|
3464
|
+
const offerKey = (list) => {
|
|
3465
|
+
try {
|
|
3466
|
+
return JSON.stringify(list.map((s) => [
|
|
3467
|
+
s.key,
|
|
3468
|
+
s.count,
|
|
3469
|
+
s.values
|
|
3470
|
+
]));
|
|
3471
|
+
} catch {
|
|
3472
|
+
return String(Math.random());
|
|
3473
|
+
}
|
|
3474
|
+
};
|
|
3475
|
+
/** Equality-guarded so a re-published identical list costs no notify (no re-render loop). */
|
|
3476
|
+
function setFilterSuggestion(next) {
|
|
3477
|
+
const list = next == null ? [] : Array.isArray(next) ? next.filter(Boolean) : [next];
|
|
3478
|
+
if (offerKey(list) === offerKey(ctrl.filterSuggestions)) return;
|
|
3479
|
+
ctrl.filterSuggestions = list;
|
|
3480
|
+
ctrl.filterSuggestion = list[0] ?? null;
|
|
3481
|
+
notify();
|
|
3482
|
+
}
|
|
3195
3483
|
async function setSearchTerms(terms) {
|
|
3196
3484
|
ctrl.searchTerms = (terms ?? []).filter((t) => t && String(t.value ?? "") !== "");
|
|
3485
|
+
ctrl.filterSuggestion = null;
|
|
3486
|
+
ctrl.filterSuggestions = [];
|
|
3197
3487
|
groupPageIndex = 0;
|
|
3198
3488
|
bumpSummary("search");
|
|
3199
3489
|
if (serverMode()) {
|
|
@@ -3633,48 +3923,13 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
3633
3923
|
* exactly as every other request does.
|
|
3634
3924
|
*/
|
|
3635
3925
|
async function distinctViaApply(store, field, options) {
|
|
3636
|
-
if (applyGate.skip) return null;
|
|
3637
|
-
if (parseFieldPath(field).hasWildcard) return null;
|
|
3638
|
-
const selector = isPath(field) ? toODataSelector(field) : field;
|
|
3639
|
-
if (!selector) return null;
|
|
3640
|
-
const apply = `groupby((${selector}),aggregate($count as count))`;
|
|
3641
|
-
const odataFilter = options?.filter != null ? arrayToODataString(options.filter) : "";
|
|
3642
|
-
const clause = odataFilter ? `filter(${odataFilter})/${apply}` : apply;
|
|
3643
3926
|
const top = typeof options?.take === "number" && options.take >= 0 ? options.take : void 0;
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
rows = await loadApply(store, clause, { top });
|
|
3647
|
-
} catch (err) {
|
|
3648
|
-
applyGate.reject(err);
|
|
3649
|
-
return null;
|
|
3650
|
-
}
|
|
3651
|
-
if (!rows) return null;
|
|
3652
|
-
if (!rows.length) return [];
|
|
3653
|
-
const first = rows[0];
|
|
3654
|
-
if (!first || typeof first !== "object" || typeof first.count !== "number") return null;
|
|
3655
|
-
if (!isRolledUp(rows, [field, "count"])) return null;
|
|
3656
|
-
const path = isPath(field);
|
|
3657
|
-
return sortColumnValues(rows.map((r) => ({
|
|
3658
|
-
value: path ? getFieldValue(r, field) : r[field],
|
|
3659
|
-
count: Number(r.count) || 0
|
|
3660
|
-
})));
|
|
3927
|
+
const rows = await groupCountViaApply(store, field, options?.filter ?? null, applyGate, { top });
|
|
3928
|
+
return rows ? sortColumnValues(rows) : null;
|
|
3661
3929
|
}
|
|
3662
3930
|
/** Count occurrences of `field` across `rows` into a sorted `{value,count}[]`. */
|
|
3663
3931
|
function distinctFromRows(rows, field) {
|
|
3664
|
-
|
|
3665
|
-
const bump = (v) => {
|
|
3666
|
-
counts.set(v, (counts.get(v) ?? 0) + 1);
|
|
3667
|
-
};
|
|
3668
|
-
const path = isPath(field);
|
|
3669
|
-
for (const r of rows) if (path) {
|
|
3670
|
-
const v = getFieldValue(r, field);
|
|
3671
|
-
if (Array.isArray(v)) v.forEach(bump);
|
|
3672
|
-
else bump(v);
|
|
3673
|
-
} else bump(r?.[field]);
|
|
3674
|
-
return sortColumnValues([...counts.entries()].map(([value, count]) => ({
|
|
3675
|
-
value,
|
|
3676
|
-
count
|
|
3677
|
-
})));
|
|
3932
|
+
return sortColumnValues(countValues(rows, field));
|
|
3678
3933
|
}
|
|
3679
3934
|
async function distinctValues(field, options) {
|
|
3680
3935
|
if (!field) return [];
|
|
@@ -3787,6 +4042,41 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
3787
4042
|
});
|
|
3788
4043
|
ctrl.sorts = marked.map((m) => m.s);
|
|
3789
4044
|
}
|
|
4045
|
+
/**
|
|
4046
|
+
* The source selector a column DECLARED via `sort.selector`, if any — what the
|
|
4047
|
+
* DataSource / array source orders by in place of the field. Resolved like
|
|
4048
|
+
* `declaredSortIndex`: central `props.th` config first, then the element's own
|
|
4049
|
+
* `:sort.prop`. A blank string counts as not declared.
|
|
4050
|
+
*/
|
|
4051
|
+
function declaredSortSelector(field) {
|
|
4052
|
+
const sel = declaredSortConfig(field).selector;
|
|
4053
|
+
return typeof sel === "string" && sel.trim() ? sel.trim() : void 0;
|
|
4054
|
+
}
|
|
4055
|
+
/**
|
|
4056
|
+
* A column's declared sort OBJECT — the element's `:sort.prop` with central
|
|
4057
|
+
* `props.th` config merged over it (props win key by key, as everywhere). `{}`
|
|
4058
|
+
* for `sort: true` / no config.
|
|
4059
|
+
*/
|
|
4060
|
+
function declaredSortConfig(field) {
|
|
4061
|
+
const asObj = (sort) => typeof sort === "object" && sort ? sort : {};
|
|
4062
|
+
let fromEl = {};
|
|
4063
|
+
for (const el of columnEls) if (el.field === field && typeof el.sort === "object" && el.sort) {
|
|
4064
|
+
fromEl = asObj(el.sort);
|
|
4065
|
+
break;
|
|
4066
|
+
}
|
|
4067
|
+
return {
|
|
4068
|
+
...fromEl,
|
|
4069
|
+
...asObj((elementProps.th ?? []).find((c) => c?.field === field)?.sort)
|
|
4070
|
+
};
|
|
4071
|
+
}
|
|
4072
|
+
/**
|
|
4073
|
+
* Whether a sorted column is sorted IN THE BROWSER — its selector fans out over a
|
|
4074
|
+
* collection (`[*]`, which no source can order by) or it declares an `aggregate`.
|
|
4075
|
+
*/
|
|
4076
|
+
function isBrowserSortKey(field) {
|
|
4077
|
+
const sel = declaredSortSelector(field);
|
|
4078
|
+
return !!sel && parseFieldPath(sel).hasWildcard || !!declaredSortConfig(field).aggregate;
|
|
4079
|
+
}
|
|
3790
4080
|
/** Keep the single-value mirrors pointing at the primary key. */
|
|
3791
4081
|
function syncPrimarySort() {
|
|
3792
4082
|
ctrl.sortField = ctrl.sorts[0]?.field ?? null;
|
|
@@ -3975,6 +4265,11 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
3975
4265
|
* see the intermediate full-list state.
|
|
3976
4266
|
*/
|
|
3977
4267
|
async function getData() {
|
|
4268
|
+
if (browserRows && browserSortActive()) return [...browserRows];
|
|
4269
|
+
return readAllFromSource();
|
|
4270
|
+
}
|
|
4271
|
+
/** `getData`'s read — every matching row from the source, in its own order. */
|
|
4272
|
+
async function readAllFromSource() {
|
|
3978
4273
|
const s = bound;
|
|
3979
4274
|
if (!s) return [];
|
|
3980
4275
|
const loadOptions = {};
|
|
@@ -4041,4 +4336,4 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
4041
4336
|
}
|
|
4042
4337
|
|
|
4043
4338
|
//#endregion
|
|
4044
|
-
export {
|
|
4339
|
+
export { checkState as a, setAllChecked as c, buildDateTree as i, setChecked as l, countTuples as n, minimize as o, groupCountsViaApply as r, seedFromRanges as s, monoDataGrid as t };
|
|
@@ -99,31 +99,36 @@ function decorateEvent(event, detail) {
|
|
|
99
99
|
* dispatchMonoEvent(this, 'loading-change', detail) // loading-change + loadingChange + mno-loading-change + mnoLoadingChange
|
|
100
100
|
*/
|
|
101
101
|
function dispatchMonoEvent(target, name, detail, options = {}) {
|
|
102
|
+
const cancelable = !!options.cancelable;
|
|
102
103
|
const init = {
|
|
103
104
|
detail,
|
|
104
105
|
bubbles: true,
|
|
105
|
-
composed: true
|
|
106
|
+
composed: true,
|
|
107
|
+
cancelable
|
|
106
108
|
};
|
|
109
|
+
let allowed = true;
|
|
107
110
|
const camel = toCamelEventName(`mno-${name}`);
|
|
108
|
-
target.dispatchEvent(new CustomEvent(`mno-${name}`, init));
|
|
109
|
-
target.dispatchEvent(new CustomEvent(camel, init));
|
|
111
|
+
allowed = target.dispatchEvent(new CustomEvent(`mno-${name}`, init)) && allowed;
|
|
112
|
+
allowed = target.dispatchEvent(new CustomEvent(camel, init)) && allowed;
|
|
110
113
|
const alias = options.alias === false ? null : options.alias ?? name;
|
|
111
|
-
if (!alias) return;
|
|
114
|
+
if (!alias) return allowed;
|
|
112
115
|
const fromDetail = detail?.sourceEvent;
|
|
113
116
|
const source = options.sourceEvent !== void 0 ? options.sourceEvent : fromDetail instanceof Event ? fromDetail : null;
|
|
114
117
|
if (source && source.type === alias && reachesHost(source, target)) {
|
|
115
118
|
decorateEvent(source, detail);
|
|
116
|
-
return;
|
|
119
|
+
return allowed;
|
|
117
120
|
}
|
|
118
|
-
if (MONO_DEVICE_EVENTS.has(alias)) return;
|
|
121
|
+
if (MONO_DEVICE_EVENTS.has(alias)) return allowed;
|
|
119
122
|
const plainInit = {
|
|
120
123
|
detail,
|
|
121
124
|
bubbles: !MONO_NON_BUBBLING_ALIASES.has(alias),
|
|
122
|
-
composed: true
|
|
125
|
+
composed: true,
|
|
126
|
+
cancelable
|
|
123
127
|
};
|
|
124
|
-
target.dispatchEvent(new CustomEvent(alias, plainInit));
|
|
128
|
+
allowed = target.dispatchEvent(new CustomEvent(alias, plainInit)) && allowed;
|
|
125
129
|
const plainCamel = toCamelEventName(alias);
|
|
126
|
-
if (plainCamel !== alias) target.dispatchEvent(new CustomEvent(plainCamel, plainInit));
|
|
130
|
+
if (plainCamel !== alias) allowed = target.dispatchEvent(new CustomEvent(plainCamel, plainInit)) && allowed;
|
|
131
|
+
return allowed;
|
|
127
132
|
}
|
|
128
133
|
|
|
129
134
|
//#endregion
|