@mono-lit/helper 0.0.8 → 0.0.9
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/index.js +3 -3
- package/dist/{index.node-CLqE8F8P.js → index.node-DTqDBca7.js} +2 -2
- package/dist/index.node.js +3 -3
- package/dist/{mono-data-dropdown-DUXo_jxd.js → mono-data-dropdown-B2iRpJuI.js} +1 -1
- package/dist/{mono-data-grid-Bkr-e1-i.js → mono-data-grid-e9ZVBlNN.js} +202 -5
- package/dist/{mono-data-grid-Bb00QM72.js → mono-data-grid-llJCX9MC.js} +202 -5
- package/dist/src/components/table/mono-data-grid.d.ts +36 -0
- package/dist/ui/dropdown-table.js +1 -1
- package/dist/ui/index.css +13 -5
- package/dist/ui/shadow/dropdown-table.js +1 -1
- package/dist/ui/shadow/table.js +2 -2
- package/dist/ui/table.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,16 +3,16 @@ import { a as buildGroups, c as isGroupNode, o as collectGroupPaths, s as flatte
|
|
|
3
3
|
import { _ as plainSearchFields, b as searchRemoteFilter, c as resolveErrorMessages, d as DEFAULT_SEARCH_OPERATION, f as MonoSourceSearch, g as parseSearchValue, h as mergeSearchFields, l as setErrorMessages, m as isFoldableSearch, n as describeError, p as SEARCH_FIELDS_KEYS, r as errorStatus, s as normalizeError, t as DEFAULT_ERROR_MESSAGES, v as readSearchField, x as searchRowPredicate, y as resolveSearchFields } from "./normalize-error-D93O4q8g.js";
|
|
4
4
|
import { h as monoArraySource } from "./data-source-options-fxT5QIX4.js";
|
|
5
5
|
import { t as resolveMaybeReactive } from "./reactive-Dtd-esHO.js";
|
|
6
|
-
import { t as monoDataGrid } from "./mono-data-grid-
|
|
6
|
+
import { t as monoDataGrid } from "./mono-data-grid-llJCX9MC.js";
|
|
7
7
|
import { d as OPERATOR_ARITY, l as treeToArray, m as operatorsFor, n as arrayToTree, s as odataStringToArray, t as arrayToODataString, u as DEFAULT_TEXTS } from "./filter-odata-Bi27XUpQ.js";
|
|
8
8
|
import { t as monoFilterBuilder } from "./filter-builder-C0T3pMx2.js";
|
|
9
9
|
import { C as resetMonoSkeleton, a as resetMonoUI, c as stopMonoSizeAttributes, i as getMonoUIStatus, m as isMonoSsrApp, n as createMonoUI, o as applyMonoSizeAttributes, p as getMonoSkeletonStatus, r as getMonoUI, s as startMonoSizeAttributes } from "./mono-ui-kvLVIf1V.js";
|
|
10
10
|
import { t as monoForm } from "./mono-form-controller-BrA10erm.js";
|
|
11
11
|
import { t as monoModal } from "./mono-modal-controller-ClObbHUs.js";
|
|
12
12
|
import { i as composeApply, n as buildChartApply, r as buildChartOdataRequest, t as monoChart } from "./mono-data-chart-NKPdAgVq.js";
|
|
13
|
-
import { t as monoDataDropdown } from "./mono-data-dropdown-
|
|
13
|
+
import { t as monoDataDropdown } from "./mono-data-dropdown-B2iRpJuI.js";
|
|
14
14
|
import { a as monoTooltip, c as getMonoTooltipGlobal, t as controlMonoTooltip } from "./control-tooltip-CoPD37_h.js";
|
|
15
15
|
import { a as resetMonoTooltip, n as createMonoTooltip, r as destroyAllMonoTooltips } from "./tooltip-Cu5IrDS9.js";
|
|
16
|
-
import { _ as DEFAULT_FLAVOR, a as flavors, b as themePresets, c as getCurrentFlavor, d as getThemeData, f as isValidFlavor, g as themes, h as resetTheme, i as createThemeClass, l as getCurrentTheme, m as resetFlavor, n as applyTheme, o as getAllFlavors, p as isValidTheme, r as createFlavorClass, s as getAllThemes, t as applyFlavor, u as getFlavorData, v as DEFAULT_THEME, y as flavorPresets } from "./index.node-
|
|
16
|
+
import { _ as DEFAULT_FLAVOR, a as flavors, b as themePresets, c as getCurrentFlavor, d as getThemeData, f as isValidFlavor, g as themes, h as resetTheme, i as createThemeClass, l as getCurrentTheme, m as resetFlavor, n as applyTheme, o as getAllFlavors, p as isValidTheme, r as createFlavorClass, s as getAllThemes, t as applyFlavor, u as getFlavorData, v as DEFAULT_THEME, y as flavorPresets } from "./index.node-DTqDBca7.js";
|
|
17
17
|
|
|
18
18
|
export { DEFAULT_ERROR_MESSAGES, DEFAULT_FLAVOR, DEFAULT_SEARCH_OPERATION, DEFAULT_THEME, OPERATOR_ARITY as MONO_FILTER_OPERATOR_ARITY, DEFAULT_TEXTS as MONO_FILTER_TEXTS, MonoSourceSearch, SEARCH_FIELDS_KEYS, applyFlavor, applyMonoSizeAttributes, applyTheme, arrayToODataString, arrayToTree, buildChartApply, buildChartOdataRequest, buildGroups, collectGroupPaths, composeApply, monoChart as controlMonoChart, monoChart, monoDataDropdown as controlMonoDataDropdown, monoDataDropdown, monoFilterBuilder as controlMonoFilterBuilder, monoFilterBuilder, monoForm as controlMonoForm, monoForm, monoModal as controlMonoModal, monoModal, monoDataGrid as controlMonoTable, monoDataGrid, controlMonoTooltip, createFlavorClass, createMonoTooltip, createMonoUI, createThemeClass, describeError, destroyAllMonoTooltips, errorStatus, flattenLeaves, flavorPresets, flavors, getAllFlavors, getAllThemes, getCurrentFlavor, getCurrentTheme, getFieldValue, getFlavorData, getMonoSkeletonStatus, getMonoTooltipGlobal, getMonoUI, getMonoUIStatus, getThemeData, isFoldableSearch, isGroupNode, isMonoSsrApp, isPath, isValidFlavor, isValidTheme, mergePatch, mergeSearchFields, monoArraySource, operatorsFor as monoFilterOperatorsFor, monoTooltip, normalizeError, odataStringToArray, parseFieldPath, parseSearchValue, plainSearchFields, readSearchField, resetFlavor, resetMonoSkeleton, resetMonoTooltip, resetMonoUI, resetTheme, resolveErrorMessages, resolveMaybeReactive, resolveSearchFields, searchRemoteFilter, searchRowPredicate, setErrorMessages, setFieldValue, startMonoSizeAttributes, stopMonoSizeAttributes, themePresets, themes, toODataClause, toODataSelector, treeToArray };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./normalize-error-D93O4q8g.js";
|
|
2
|
-
import "./mono-data-grid-
|
|
2
|
+
import "./mono-data-grid-llJCX9MC.js";
|
|
3
3
|
import "./mono-ui-kvLVIf1V.js";
|
|
4
4
|
import "./mono-data-chart-NKPdAgVq.js";
|
|
5
|
-
import "./mono-data-dropdown-
|
|
5
|
+
import "./mono-data-dropdown-B2iRpJuI.js";
|
|
6
6
|
import "./tooltip-Cu5IrDS9.js";
|
|
7
7
|
|
|
8
8
|
//#region src/data/theme/presets.json
|
package/dist/index.node.js
CHANGED
|
@@ -3,16 +3,16 @@ import { a as buildGroups, c as isGroupNode, o as collectGroupPaths, s as flatte
|
|
|
3
3
|
import { _ as plainSearchFields, b as searchRemoteFilter, c as resolveErrorMessages, d as DEFAULT_SEARCH_OPERATION, f as MonoSourceSearch, g as parseSearchValue, h as mergeSearchFields, l as setErrorMessages, m as isFoldableSearch, n as describeError, p as SEARCH_FIELDS_KEYS, r as errorStatus, s as normalizeError, t as DEFAULT_ERROR_MESSAGES, v as readSearchField, x as searchRowPredicate, y as resolveSearchFields } from "./normalize-error-D93O4q8g.js";
|
|
4
4
|
import { h as monoArraySource } from "./data-source-options-fxT5QIX4.js";
|
|
5
5
|
import { t as resolveMaybeReactive } from "./reactive-Dtd-esHO.js";
|
|
6
|
-
import { t as monoDataGrid } from "./mono-data-grid-
|
|
6
|
+
import { t as monoDataGrid } from "./mono-data-grid-llJCX9MC.js";
|
|
7
7
|
import { d as OPERATOR_ARITY, l as treeToArray, m as operatorsFor, n as arrayToTree, s as odataStringToArray, t as arrayToODataString, u as DEFAULT_TEXTS } from "./filter-odata-Bi27XUpQ.js";
|
|
8
8
|
import { t as monoFilterBuilder } from "./filter-builder-C0T3pMx2.js";
|
|
9
9
|
import { C as resetMonoSkeleton, a as resetMonoUI, c as stopMonoSizeAttributes, i as getMonoUIStatus, m as isMonoSsrApp, n as createMonoUI, o as applyMonoSizeAttributes, p as getMonoSkeletonStatus, r as getMonoUI, s as startMonoSizeAttributes } from "./mono-ui-kvLVIf1V.js";
|
|
10
10
|
import { t as monoForm } from "./mono-form-controller-BrA10erm.js";
|
|
11
11
|
import { t as monoModal } from "./mono-modal-controller-ClObbHUs.js";
|
|
12
12
|
import { i as composeApply, n as buildChartApply, r as buildChartOdataRequest, t as monoChart } from "./mono-data-chart-NKPdAgVq.js";
|
|
13
|
-
import { t as monoDataDropdown } from "./mono-data-dropdown-
|
|
13
|
+
import { t as monoDataDropdown } from "./mono-data-dropdown-B2iRpJuI.js";
|
|
14
14
|
import { a as monoTooltip, c as getMonoTooltipGlobal, t as controlMonoTooltip } from "./control-tooltip-CoPD37_h.js";
|
|
15
15
|
import { a as resetMonoTooltip, n as createMonoTooltip, r as destroyAllMonoTooltips } from "./tooltip-Cu5IrDS9.js";
|
|
16
|
-
import { _ as DEFAULT_FLAVOR, a as flavors, b as themePresets, c as getCurrentFlavor, d as getThemeData, f as isValidFlavor, g as themes, h as resetTheme, i as createThemeClass, l as getCurrentTheme, m as resetFlavor, n as applyTheme, o as getAllFlavors, p as isValidTheme, r as createFlavorClass, s as getAllThemes, t as applyFlavor, u as getFlavorData, v as DEFAULT_THEME, y as flavorPresets } from "./index.node-
|
|
16
|
+
import { _ as DEFAULT_FLAVOR, a as flavors, b as themePresets, c as getCurrentFlavor, d as getThemeData, f as isValidFlavor, g as themes, h as resetTheme, i as createThemeClass, l as getCurrentTheme, m as resetFlavor, n as applyTheme, o as getAllFlavors, p as isValidTheme, r as createFlavorClass, s as getAllThemes, t as applyFlavor, u as getFlavorData, v as DEFAULT_THEME, y as flavorPresets } from "./index.node-DTqDBca7.js";
|
|
17
17
|
|
|
18
18
|
export { DEFAULT_ERROR_MESSAGES, DEFAULT_FLAVOR, DEFAULT_SEARCH_OPERATION, DEFAULT_THEME, OPERATOR_ARITY as MONO_FILTER_OPERATOR_ARITY, DEFAULT_TEXTS as MONO_FILTER_TEXTS, MonoSourceSearch, SEARCH_FIELDS_KEYS, applyFlavor, applyMonoSizeAttributes, applyTheme, arrayToODataString, arrayToTree, buildChartApply, buildChartOdataRequest, buildGroups, collectGroupPaths, composeApply, monoChart as controlMonoChart, monoChart, monoDataDropdown as controlMonoDataDropdown, monoDataDropdown, monoFilterBuilder as controlMonoFilterBuilder, monoFilterBuilder, monoForm as controlMonoForm, monoForm, monoModal as controlMonoModal, monoModal, monoDataGrid as controlMonoTable, monoDataGrid, controlMonoTooltip, createFlavorClass, createMonoTooltip, createMonoUI, createThemeClass, describeError, destroyAllMonoTooltips, errorStatus, flattenLeaves, flavorPresets, flavors, getAllFlavors, getAllThemes, getCurrentFlavor, getCurrentTheme, getFieldValue, getFlavorData, getMonoSkeletonStatus, getMonoTooltipGlobal, getMonoUI, getMonoUIStatus, getThemeData, isFoldableSearch, isGroupNode, isMonoSsrApp, isPath, isValidFlavor, isValidTheme, mergePatch, mergeSearchFields, monoArraySource, operatorsFor as monoFilterOperatorsFor, monoTooltip, normalizeError, odataStringToArray, parseFieldPath, parseSearchValue, plainSearchFields, readSearchField, resetFlavor, resetMonoSkeleton, resetMonoTooltip, resetMonoUI, resetTheme, resolveErrorMessages, resolveMaybeReactive, resolveSearchFields, searchRemoteFilter, searchRowPredicate, setErrorMessages, setFieldValue, startMonoSizeAttributes, stopMonoSizeAttributes, themePresets, themes, toODataClause, toODataSelector, treeToArray };
|
|
@@ -444,6 +444,9 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
444
444
|
const chunkSize = Math.max(1, opts.chunkSize ?? 100);
|
|
445
445
|
let suppressSync = false;
|
|
446
446
|
let allRows = [];
|
|
447
|
+
let browserRows = null;
|
|
448
|
+
let browserPageIndex = 0;
|
|
449
|
+
let browserPageSize = 0;
|
|
447
450
|
let scrollMode = "off";
|
|
448
451
|
let accumulated = [];
|
|
449
452
|
let scrollNextPage = 0;
|
|
@@ -2147,16 +2150,21 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2147
2150
|
* column sort follows — applied to the group field itself if it is one.
|
|
2148
2151
|
*/
|
|
2149
2152
|
function effectiveSort() {
|
|
2150
|
-
const keys = ctrl.sorts.map((s) => ({
|
|
2151
|
-
|
|
2153
|
+
const keys = ctrl.sorts.filter((s) => !isBrowserSortKey(s.field)).map((s) => ({
|
|
2154
|
+
field: s.field,
|
|
2155
|
+
selector: declaredSortSelector(s.field) ?? s.field,
|
|
2152
2156
|
desc: s.order === "desc"
|
|
2153
2157
|
}));
|
|
2154
|
-
|
|
2158
|
+
const entry = (k) => ({
|
|
2159
|
+
selector: k.selector,
|
|
2160
|
+
desc: k.desc
|
|
2161
|
+
});
|
|
2162
|
+
if (!groupFields.length) return keys.length ? keys.map(entry) : null;
|
|
2155
2163
|
const list = groupFields.map((f) => ({
|
|
2156
2164
|
selector: f,
|
|
2157
|
-
desc: keys.find((k) => k.
|
|
2165
|
+
desc: keys.find((k) => k.field === f)?.desc ?? false
|
|
2158
2166
|
}));
|
|
2159
|
-
for (const k of keys) if (!groupFields.includes(k.
|
|
2167
|
+
for (const k of keys) if (!groupFields.includes(k.field)) list.push(entry(k));
|
|
2160
2168
|
return list;
|
|
2161
2169
|
}
|
|
2162
2170
|
/**
|
|
@@ -2571,6 +2579,10 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2571
2579
|
syncScroll();
|
|
2572
2580
|
return;
|
|
2573
2581
|
}
|
|
2582
|
+
if (browserRows && browserSortActive()) {
|
|
2583
|
+
syncBrowser();
|
|
2584
|
+
return;
|
|
2585
|
+
}
|
|
2574
2586
|
if (pageSizeAll) {
|
|
2575
2587
|
ctrl.grouped = false;
|
|
2576
2588
|
ctrl.items = allRows;
|
|
@@ -2734,6 +2746,11 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2734
2746
|
await loadScrollPage(true);
|
|
2735
2747
|
return;
|
|
2736
2748
|
}
|
|
2749
|
+
if (browserSortActive()) {
|
|
2750
|
+
await loadBrowserSorted();
|
|
2751
|
+
return;
|
|
2752
|
+
}
|
|
2753
|
+
browserRows = null;
|
|
2737
2754
|
if (pageSizeAll && !isGrouped()) {
|
|
2738
2755
|
await loadAllChunked();
|
|
2739
2756
|
return;
|
|
@@ -2755,6 +2772,11 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2755
2772
|
await loadScrollPage(true);
|
|
2756
2773
|
return;
|
|
2757
2774
|
}
|
|
2775
|
+
if (browserSortActive()) {
|
|
2776
|
+
await loadBrowserSorted();
|
|
2777
|
+
return;
|
|
2778
|
+
}
|
|
2779
|
+
browserRows = null;
|
|
2758
2780
|
if (pageSizeAll && !isGrouped()) {
|
|
2759
2781
|
await loadAllChunked();
|
|
2760
2782
|
return;
|
|
@@ -2791,6 +2813,11 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2791
2813
|
if (serverMode()) await fetchVisibleRows();
|
|
2792
2814
|
return;
|
|
2793
2815
|
}
|
|
2816
|
+
if (browserRows && browserSortActive()) {
|
|
2817
|
+
browserPageIndex = Math.max(0, pageIndex);
|
|
2818
|
+
syncBrowser();
|
|
2819
|
+
return;
|
|
2820
|
+
}
|
|
2794
2821
|
const s = bound;
|
|
2795
2822
|
if (!s) return;
|
|
2796
2823
|
s.pageIndex?.(Math.max(0, pageIndex));
|
|
@@ -2808,6 +2835,15 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2808
2835
|
}
|
|
2809
2836
|
const s = bound;
|
|
2810
2837
|
if (!s) return;
|
|
2838
|
+
if (browserRows && browserSortActive()) {
|
|
2839
|
+
if (!all) {
|
|
2840
|
+
browserPageSize = Math.max(1, pageSize);
|
|
2841
|
+
s.pageSize?.(browserPageSize);
|
|
2842
|
+
}
|
|
2843
|
+
browserPageIndex = 0;
|
|
2844
|
+
syncBrowser();
|
|
2845
|
+
return;
|
|
2846
|
+
}
|
|
2811
2847
|
if (all) {
|
|
2812
2848
|
await loadAllChunked();
|
|
2813
2849
|
return;
|
|
@@ -2854,6 +2890,127 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2854
2890
|
ctrl.loading = bound?.isLoading?.() ?? false;
|
|
2855
2891
|
sync();
|
|
2856
2892
|
}
|
|
2893
|
+
const BROWSER_SORT_MAX_ROWS = 5e3;
|
|
2894
|
+
/** The active sort keys when ANY of them sorts in the browser, else `null`. */
|
|
2895
|
+
function browserSortKeys() {
|
|
2896
|
+
if (!ctrl.sorts.some((s) => isBrowserSortKey(s.field))) return null;
|
|
2897
|
+
return ctrl.sorts.map((s) => {
|
|
2898
|
+
const browser = isBrowserSortKey(s.field);
|
|
2899
|
+
return {
|
|
2900
|
+
field: s.field,
|
|
2901
|
+
selector: declaredSortSelector(s.field) ?? s.field,
|
|
2902
|
+
desc: s.order === "desc",
|
|
2903
|
+
aggregate: browser ? declaredSortConfig(s.field).aggregate ?? "sum" : null
|
|
2904
|
+
};
|
|
2905
|
+
});
|
|
2906
|
+
}
|
|
2907
|
+
/** Browser sort applies: a browser-sorted column is active on a flat, paged, bound table. */
|
|
2908
|
+
function browserSortActive() {
|
|
2909
|
+
return !!bound && !isGrouped() && !serverMode() && !scrollActive() && !!browserSortKeys();
|
|
2910
|
+
}
|
|
2911
|
+
/** The smallest `maxRows` any active browser-sorted column declares (default 5000). */
|
|
2912
|
+
function browserSortCap() {
|
|
2913
|
+
const caps = ctrl.sorts.filter((s) => isBrowserSortKey(s.field)).map((s) => Number(declaredSortConfig(s.field).maxRows)).filter((n) => Number.isFinite(n) && n > 0);
|
|
2914
|
+
return caps.length ? Math.min(...caps) : BROWSER_SORT_MAX_ROWS;
|
|
2915
|
+
}
|
|
2916
|
+
/** A row's matches for `selector` reduced to one sortable value. */
|
|
2917
|
+
function browserSortValue(row, selector, aggregate) {
|
|
2918
|
+
const raw = getFieldValue(row, selector);
|
|
2919
|
+
if (!aggregate) return raw;
|
|
2920
|
+
const list = Array.isArray(raw) ? raw : raw == null ? [] : [raw];
|
|
2921
|
+
if (aggregate === "count") return list.length;
|
|
2922
|
+
const nums = list.map(Number).filter((n) => Number.isFinite(n));
|
|
2923
|
+
if (!nums.length) return aggregate === "sum" ? 0 : null;
|
|
2924
|
+
if (aggregate === "min") return Math.min(...nums);
|
|
2925
|
+
if (aggregate === "max") return Math.max(...nums);
|
|
2926
|
+
const sum = nums.reduce((a, b) => a + b, 0);
|
|
2927
|
+
return aggregate === "avg" ? sum / nums.length : sum;
|
|
2928
|
+
}
|
|
2929
|
+
/** Empties last in either direction; numbers numerically; text numeric-aware. */
|
|
2930
|
+
function compareBrowserValues(a, b) {
|
|
2931
|
+
const ea = a == null || a === "";
|
|
2932
|
+
const eb = b == null || b === "";
|
|
2933
|
+
if (ea || eb) return ea === eb ? 0 : ea ? 1 : -1;
|
|
2934
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
2935
|
+
if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();
|
|
2936
|
+
return String(a).localeCompare(String(b), void 0, { numeric: true });
|
|
2937
|
+
}
|
|
2938
|
+
/** Every matching row, sorted by the active keys (stable). */
|
|
2939
|
+
function sortBrowserRows(rows) {
|
|
2940
|
+
const keys = browserSortKeys() ?? [];
|
|
2941
|
+
const decorated = rows.map((row, i) => ({
|
|
2942
|
+
row,
|
|
2943
|
+
i,
|
|
2944
|
+
v: keys.map((k) => browserSortValue(row, k.selector, k.aggregate))
|
|
2945
|
+
}));
|
|
2946
|
+
decorated.sort((x, y) => {
|
|
2947
|
+
for (let k = 0; k < keys.length; k++) {
|
|
2948
|
+
const ex = x.v[k] == null || x.v[k] === "";
|
|
2949
|
+
const ey = y.v[k] == null || y.v[k] === "";
|
|
2950
|
+
const c = compareBrowserValues(x.v[k], y.v[k]);
|
|
2951
|
+
if (c) return ex || ey ? c : keys[k].desc ? -c : c;
|
|
2952
|
+
}
|
|
2953
|
+
return x.i - y.i;
|
|
2954
|
+
});
|
|
2955
|
+
return decorated.map((d) => d.row);
|
|
2956
|
+
}
|
|
2957
|
+
/** Too many rows to sort in the browser: drop those keys, warn, load normally. */
|
|
2958
|
+
async function refuseBrowserSort(count, cap) {
|
|
2959
|
+
const fields = ctrl.sorts.filter((s) => isBrowserSortKey(s.field)).map((s) => s.field);
|
|
2960
|
+
console.warn(`[monoDataGrid] sort: "${fields.join("\", \"")}" sorts in the browser and needs every row, but ${count} match (maxRows ${cap}) — sort cleared.`);
|
|
2961
|
+
ctrl.sorts = ctrl.sorts.filter((s) => !isBrowserSortKey(s.field));
|
|
2962
|
+
syncPrimarySort();
|
|
2963
|
+
browserRows = null;
|
|
2964
|
+
applySourceSort();
|
|
2965
|
+
notify();
|
|
2966
|
+
await load();
|
|
2967
|
+
}
|
|
2968
|
+
/** Read every matching row, sort it in memory, show the first page. */
|
|
2969
|
+
async function loadBrowserSorted() {
|
|
2970
|
+
const s = bound;
|
|
2971
|
+
if (!s) return;
|
|
2972
|
+
const cap = browserSortCap();
|
|
2973
|
+
const known = s.totalCount?.();
|
|
2974
|
+
if (typeof known === "number" && known > cap) {
|
|
2975
|
+
await refuseBrowserSort(known, cap);
|
|
2976
|
+
return;
|
|
2977
|
+
}
|
|
2978
|
+
if (!browserPageSize) browserPageSize = Math.max(1, s.pageSize?.() || ctrl.pageSize || 20);
|
|
2979
|
+
ctrl.loading = true;
|
|
2980
|
+
notify();
|
|
2981
|
+
let rows = [];
|
|
2982
|
+
try {
|
|
2983
|
+
await runLoad(async () => {
|
|
2984
|
+
rows = await readAllFromSource();
|
|
2985
|
+
});
|
|
2986
|
+
} finally {
|
|
2987
|
+
ctrl.loading = false;
|
|
2988
|
+
}
|
|
2989
|
+
if (rows.length > cap) {
|
|
2990
|
+
await refuseBrowserSort(rows.length, cap);
|
|
2991
|
+
return;
|
|
2992
|
+
}
|
|
2993
|
+
browserRows = sortBrowserRows(rows);
|
|
2994
|
+
browserPageIndex = 0;
|
|
2995
|
+
sync();
|
|
2996
|
+
recomputeSummaries();
|
|
2997
|
+
}
|
|
2998
|
+
/** Map the in-memory sorted rows (current page, or all) onto `ctrl`. */
|
|
2999
|
+
function syncBrowser() {
|
|
3000
|
+
const rows = browserRows ?? [];
|
|
3001
|
+
const size = pageSizeAll ? Math.max(1, rows.length) : Math.max(1, browserPageSize);
|
|
3002
|
+
const pageCount = Math.max(1, Math.ceil(rows.length / size));
|
|
3003
|
+
browserPageIndex = Math.min(Math.max(0, browserPageIndex), pageCount - 1);
|
|
3004
|
+
const start = browserPageIndex * size;
|
|
3005
|
+
ctrl.grouped = false;
|
|
3006
|
+
ctrl.items = rows.slice(start, start + size);
|
|
3007
|
+
ctrl.pageIndex = browserPageIndex;
|
|
3008
|
+
ctrl.pageSize = size;
|
|
3009
|
+
ctrl.pageSizeAll = pageSizeAll;
|
|
3010
|
+
ctrl.totalCount = rows.length;
|
|
3011
|
+
ctrl.pageCount = pageCount;
|
|
3012
|
+
render();
|
|
3013
|
+
}
|
|
2857
3014
|
/** Scroll modes only apply to a flat (ungrouped, non-server) grid. */
|
|
2858
3015
|
function scrollActive() {
|
|
2859
3016
|
return scrollMode !== "off" && !isGrouped() && !serverMode();
|
|
@@ -3786,6 +3943,41 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
3786
3943
|
});
|
|
3787
3944
|
ctrl.sorts = marked.map((m) => m.s);
|
|
3788
3945
|
}
|
|
3946
|
+
/**
|
|
3947
|
+
* The source selector a column DECLARED via `sort.selector`, if any — what the
|
|
3948
|
+
* DataSource / array source orders by in place of the field. Resolved like
|
|
3949
|
+
* `declaredSortIndex`: central `props.th` config first, then the element's own
|
|
3950
|
+
* `:sort.prop`. A blank string counts as not declared.
|
|
3951
|
+
*/
|
|
3952
|
+
function declaredSortSelector(field) {
|
|
3953
|
+
const sel = declaredSortConfig(field).selector;
|
|
3954
|
+
return typeof sel === "string" && sel.trim() ? sel.trim() : void 0;
|
|
3955
|
+
}
|
|
3956
|
+
/**
|
|
3957
|
+
* A column's declared sort OBJECT — the element's `:sort.prop` with central
|
|
3958
|
+
* `props.th` config merged over it (props win key by key, as everywhere). `{}`
|
|
3959
|
+
* for `sort: true` / no config.
|
|
3960
|
+
*/
|
|
3961
|
+
function declaredSortConfig(field) {
|
|
3962
|
+
const asObj = (sort) => typeof sort === "object" && sort ? sort : {};
|
|
3963
|
+
let fromEl = {};
|
|
3964
|
+
for (const el of columnEls) if (el.field === field && typeof el.sort === "object" && el.sort) {
|
|
3965
|
+
fromEl = asObj(el.sort);
|
|
3966
|
+
break;
|
|
3967
|
+
}
|
|
3968
|
+
return {
|
|
3969
|
+
...fromEl,
|
|
3970
|
+
...asObj((elementProps.th ?? []).find((c) => c?.field === field)?.sort)
|
|
3971
|
+
};
|
|
3972
|
+
}
|
|
3973
|
+
/**
|
|
3974
|
+
* Whether a sorted column is sorted IN THE BROWSER — its selector fans out over a
|
|
3975
|
+
* collection (`[*]`, which no source can order by) or it declares an `aggregate`.
|
|
3976
|
+
*/
|
|
3977
|
+
function isBrowserSortKey(field) {
|
|
3978
|
+
const sel = declaredSortSelector(field);
|
|
3979
|
+
return !!sel && parseFieldPath(sel).hasWildcard || !!declaredSortConfig(field).aggregate;
|
|
3980
|
+
}
|
|
3789
3981
|
/** Keep the single-value mirrors pointing at the primary key. */
|
|
3790
3982
|
function syncPrimarySort() {
|
|
3791
3983
|
ctrl.sortField = ctrl.sorts[0]?.field ?? null;
|
|
@@ -3974,6 +4166,11 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
3974
4166
|
* see the intermediate full-list state.
|
|
3975
4167
|
*/
|
|
3976
4168
|
async function getData() {
|
|
4169
|
+
if (browserRows && browserSortActive()) return [...browserRows];
|
|
4170
|
+
return readAllFromSource();
|
|
4171
|
+
}
|
|
4172
|
+
/** `getData`'s read — every matching row from the source, in its own order. */
|
|
4173
|
+
async function readAllFromSource() {
|
|
3977
4174
|
const s = bound;
|
|
3978
4175
|
if (!s) return [];
|
|
3979
4176
|
const loadOptions = {};
|
|
@@ -445,6 +445,9 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
445
445
|
const chunkSize = Math.max(1, opts.chunkSize ?? 100);
|
|
446
446
|
let suppressSync = false;
|
|
447
447
|
let allRows = [];
|
|
448
|
+
let browserRows = null;
|
|
449
|
+
let browserPageIndex = 0;
|
|
450
|
+
let browserPageSize = 0;
|
|
448
451
|
let scrollMode = "off";
|
|
449
452
|
let accumulated = [];
|
|
450
453
|
let scrollNextPage = 0;
|
|
@@ -2148,16 +2151,21 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2148
2151
|
* column sort follows — applied to the group field itself if it is one.
|
|
2149
2152
|
*/
|
|
2150
2153
|
function effectiveSort() {
|
|
2151
|
-
const keys = ctrl.sorts.map((s) => ({
|
|
2152
|
-
|
|
2154
|
+
const keys = ctrl.sorts.filter((s) => !isBrowserSortKey(s.field)).map((s) => ({
|
|
2155
|
+
field: s.field,
|
|
2156
|
+
selector: declaredSortSelector(s.field) ?? s.field,
|
|
2153
2157
|
desc: s.order === "desc"
|
|
2154
2158
|
}));
|
|
2155
|
-
|
|
2159
|
+
const entry = (k) => ({
|
|
2160
|
+
selector: k.selector,
|
|
2161
|
+
desc: k.desc
|
|
2162
|
+
});
|
|
2163
|
+
if (!groupFields.length) return keys.length ? keys.map(entry) : null;
|
|
2156
2164
|
const list = groupFields.map((f) => ({
|
|
2157
2165
|
selector: f,
|
|
2158
|
-
desc: keys.find((k) => k.
|
|
2166
|
+
desc: keys.find((k) => k.field === f)?.desc ?? false
|
|
2159
2167
|
}));
|
|
2160
|
-
for (const k of keys) if (!groupFields.includes(k.
|
|
2168
|
+
for (const k of keys) if (!groupFields.includes(k.field)) list.push(entry(k));
|
|
2161
2169
|
return list;
|
|
2162
2170
|
}
|
|
2163
2171
|
/**
|
|
@@ -2572,6 +2580,10 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2572
2580
|
syncScroll();
|
|
2573
2581
|
return;
|
|
2574
2582
|
}
|
|
2583
|
+
if (browserRows && browserSortActive()) {
|
|
2584
|
+
syncBrowser();
|
|
2585
|
+
return;
|
|
2586
|
+
}
|
|
2575
2587
|
if (pageSizeAll) {
|
|
2576
2588
|
ctrl.grouped = false;
|
|
2577
2589
|
ctrl.items = allRows;
|
|
@@ -2735,6 +2747,11 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2735
2747
|
await loadScrollPage(true);
|
|
2736
2748
|
return;
|
|
2737
2749
|
}
|
|
2750
|
+
if (browserSortActive()) {
|
|
2751
|
+
await loadBrowserSorted();
|
|
2752
|
+
return;
|
|
2753
|
+
}
|
|
2754
|
+
browserRows = null;
|
|
2738
2755
|
if (pageSizeAll && !isGrouped()) {
|
|
2739
2756
|
await loadAllChunked();
|
|
2740
2757
|
return;
|
|
@@ -2756,6 +2773,11 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2756
2773
|
await loadScrollPage(true);
|
|
2757
2774
|
return;
|
|
2758
2775
|
}
|
|
2776
|
+
if (browserSortActive()) {
|
|
2777
|
+
await loadBrowserSorted();
|
|
2778
|
+
return;
|
|
2779
|
+
}
|
|
2780
|
+
browserRows = null;
|
|
2759
2781
|
if (pageSizeAll && !isGrouped()) {
|
|
2760
2782
|
await loadAllChunked();
|
|
2761
2783
|
return;
|
|
@@ -2792,6 +2814,11 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2792
2814
|
if (serverMode()) await fetchVisibleRows();
|
|
2793
2815
|
return;
|
|
2794
2816
|
}
|
|
2817
|
+
if (browserRows && browserSortActive()) {
|
|
2818
|
+
browserPageIndex = Math.max(0, pageIndex);
|
|
2819
|
+
syncBrowser();
|
|
2820
|
+
return;
|
|
2821
|
+
}
|
|
2795
2822
|
const s = bound;
|
|
2796
2823
|
if (!s) return;
|
|
2797
2824
|
s.pageIndex?.(Math.max(0, pageIndex));
|
|
@@ -2809,6 +2836,15 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2809
2836
|
}
|
|
2810
2837
|
const s = bound;
|
|
2811
2838
|
if (!s) return;
|
|
2839
|
+
if (browserRows && browserSortActive()) {
|
|
2840
|
+
if (!all) {
|
|
2841
|
+
browserPageSize = Math.max(1, pageSize);
|
|
2842
|
+
s.pageSize?.(browserPageSize);
|
|
2843
|
+
}
|
|
2844
|
+
browserPageIndex = 0;
|
|
2845
|
+
syncBrowser();
|
|
2846
|
+
return;
|
|
2847
|
+
}
|
|
2812
2848
|
if (all) {
|
|
2813
2849
|
await loadAllChunked();
|
|
2814
2850
|
return;
|
|
@@ -2855,6 +2891,127 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
2855
2891
|
ctrl.loading = bound?.isLoading?.() ?? false;
|
|
2856
2892
|
sync();
|
|
2857
2893
|
}
|
|
2894
|
+
const BROWSER_SORT_MAX_ROWS = 5e3;
|
|
2895
|
+
/** The active sort keys when ANY of them sorts in the browser, else `null`. */
|
|
2896
|
+
function browserSortKeys() {
|
|
2897
|
+
if (!ctrl.sorts.some((s) => isBrowserSortKey(s.field))) return null;
|
|
2898
|
+
return ctrl.sorts.map((s) => {
|
|
2899
|
+
const browser = isBrowserSortKey(s.field);
|
|
2900
|
+
return {
|
|
2901
|
+
field: s.field,
|
|
2902
|
+
selector: declaredSortSelector(s.field) ?? s.field,
|
|
2903
|
+
desc: s.order === "desc",
|
|
2904
|
+
aggregate: browser ? declaredSortConfig(s.field).aggregate ?? "sum" : null
|
|
2905
|
+
};
|
|
2906
|
+
});
|
|
2907
|
+
}
|
|
2908
|
+
/** Browser sort applies: a browser-sorted column is active on a flat, paged, bound table. */
|
|
2909
|
+
function browserSortActive() {
|
|
2910
|
+
return !!bound && !isGrouped() && !serverMode() && !scrollActive() && !!browserSortKeys();
|
|
2911
|
+
}
|
|
2912
|
+
/** The smallest `maxRows` any active browser-sorted column declares (default 5000). */
|
|
2913
|
+
function browserSortCap() {
|
|
2914
|
+
const caps = ctrl.sorts.filter((s) => isBrowserSortKey(s.field)).map((s) => Number(declaredSortConfig(s.field).maxRows)).filter((n) => Number.isFinite(n) && n > 0);
|
|
2915
|
+
return caps.length ? Math.min(...caps) : BROWSER_SORT_MAX_ROWS;
|
|
2916
|
+
}
|
|
2917
|
+
/** A row's matches for `selector` reduced to one sortable value. */
|
|
2918
|
+
function browserSortValue(row, selector, aggregate) {
|
|
2919
|
+
const raw = getFieldValue(row, selector);
|
|
2920
|
+
if (!aggregate) return raw;
|
|
2921
|
+
const list = Array.isArray(raw) ? raw : raw == null ? [] : [raw];
|
|
2922
|
+
if (aggregate === "count") return list.length;
|
|
2923
|
+
const nums = list.map(Number).filter((n) => Number.isFinite(n));
|
|
2924
|
+
if (!nums.length) return aggregate === "sum" ? 0 : null;
|
|
2925
|
+
if (aggregate === "min") return Math.min(...nums);
|
|
2926
|
+
if (aggregate === "max") return Math.max(...nums);
|
|
2927
|
+
const sum = nums.reduce((a, b) => a + b, 0);
|
|
2928
|
+
return aggregate === "avg" ? sum / nums.length : sum;
|
|
2929
|
+
}
|
|
2930
|
+
/** Empties last in either direction; numbers numerically; text numeric-aware. */
|
|
2931
|
+
function compareBrowserValues(a, b) {
|
|
2932
|
+
const ea = a == null || a === "";
|
|
2933
|
+
const eb = b == null || b === "";
|
|
2934
|
+
if (ea || eb) return ea === eb ? 0 : ea ? 1 : -1;
|
|
2935
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
2936
|
+
if (a instanceof Date && b instanceof Date) return a.getTime() - b.getTime();
|
|
2937
|
+
return String(a).localeCompare(String(b), void 0, { numeric: true });
|
|
2938
|
+
}
|
|
2939
|
+
/** Every matching row, sorted by the active keys (stable). */
|
|
2940
|
+
function sortBrowserRows(rows) {
|
|
2941
|
+
const keys = browserSortKeys() ?? [];
|
|
2942
|
+
const decorated = rows.map((row, i) => ({
|
|
2943
|
+
row,
|
|
2944
|
+
i,
|
|
2945
|
+
v: keys.map((k) => browserSortValue(row, k.selector, k.aggregate))
|
|
2946
|
+
}));
|
|
2947
|
+
decorated.sort((x, y) => {
|
|
2948
|
+
for (let k = 0; k < keys.length; k++) {
|
|
2949
|
+
const ex = x.v[k] == null || x.v[k] === "";
|
|
2950
|
+
const ey = y.v[k] == null || y.v[k] === "";
|
|
2951
|
+
const c = compareBrowserValues(x.v[k], y.v[k]);
|
|
2952
|
+
if (c) return ex || ey ? c : keys[k].desc ? -c : c;
|
|
2953
|
+
}
|
|
2954
|
+
return x.i - y.i;
|
|
2955
|
+
});
|
|
2956
|
+
return decorated.map((d) => d.row);
|
|
2957
|
+
}
|
|
2958
|
+
/** Too many rows to sort in the browser: drop those keys, warn, load normally. */
|
|
2959
|
+
async function refuseBrowserSort(count, cap) {
|
|
2960
|
+
const fields = ctrl.sorts.filter((s) => isBrowserSortKey(s.field)).map((s) => s.field);
|
|
2961
|
+
console.warn(`[monoDataGrid] sort: "${fields.join("\", \"")}" sorts in the browser and needs every row, but ${count} match (maxRows ${cap}) — sort cleared.`);
|
|
2962
|
+
ctrl.sorts = ctrl.sorts.filter((s) => !isBrowserSortKey(s.field));
|
|
2963
|
+
syncPrimarySort();
|
|
2964
|
+
browserRows = null;
|
|
2965
|
+
applySourceSort();
|
|
2966
|
+
notify();
|
|
2967
|
+
await load();
|
|
2968
|
+
}
|
|
2969
|
+
/** Read every matching row, sort it in memory, show the first page. */
|
|
2970
|
+
async function loadBrowserSorted() {
|
|
2971
|
+
const s = bound;
|
|
2972
|
+
if (!s) return;
|
|
2973
|
+
const cap = browserSortCap();
|
|
2974
|
+
const known = s.totalCount?.();
|
|
2975
|
+
if (typeof known === "number" && known > cap) {
|
|
2976
|
+
await refuseBrowserSort(known, cap);
|
|
2977
|
+
return;
|
|
2978
|
+
}
|
|
2979
|
+
if (!browserPageSize) browserPageSize = Math.max(1, s.pageSize?.() || ctrl.pageSize || 20);
|
|
2980
|
+
ctrl.loading = true;
|
|
2981
|
+
notify();
|
|
2982
|
+
let rows = [];
|
|
2983
|
+
try {
|
|
2984
|
+
await runLoad(async () => {
|
|
2985
|
+
rows = await readAllFromSource();
|
|
2986
|
+
});
|
|
2987
|
+
} finally {
|
|
2988
|
+
ctrl.loading = false;
|
|
2989
|
+
}
|
|
2990
|
+
if (rows.length > cap) {
|
|
2991
|
+
await refuseBrowserSort(rows.length, cap);
|
|
2992
|
+
return;
|
|
2993
|
+
}
|
|
2994
|
+
browserRows = sortBrowserRows(rows);
|
|
2995
|
+
browserPageIndex = 0;
|
|
2996
|
+
sync();
|
|
2997
|
+
recomputeSummaries();
|
|
2998
|
+
}
|
|
2999
|
+
/** Map the in-memory sorted rows (current page, or all) onto `ctrl`. */
|
|
3000
|
+
function syncBrowser() {
|
|
3001
|
+
const rows = browserRows ?? [];
|
|
3002
|
+
const size = pageSizeAll ? Math.max(1, rows.length) : Math.max(1, browserPageSize);
|
|
3003
|
+
const pageCount = Math.max(1, Math.ceil(rows.length / size));
|
|
3004
|
+
browserPageIndex = Math.min(Math.max(0, browserPageIndex), pageCount - 1);
|
|
3005
|
+
const start = browserPageIndex * size;
|
|
3006
|
+
ctrl.grouped = false;
|
|
3007
|
+
ctrl.items = rows.slice(start, start + size);
|
|
3008
|
+
ctrl.pageIndex = browserPageIndex;
|
|
3009
|
+
ctrl.pageSize = size;
|
|
3010
|
+
ctrl.pageSizeAll = pageSizeAll;
|
|
3011
|
+
ctrl.totalCount = rows.length;
|
|
3012
|
+
ctrl.pageCount = pageCount;
|
|
3013
|
+
render();
|
|
3014
|
+
}
|
|
2858
3015
|
/** Scroll modes only apply to a flat (ungrouped, non-server) grid. */
|
|
2859
3016
|
function scrollActive() {
|
|
2860
3017
|
return scrollMode !== "off" && !isGrouped() && !serverMode();
|
|
@@ -3787,6 +3944,41 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
3787
3944
|
});
|
|
3788
3945
|
ctrl.sorts = marked.map((m) => m.s);
|
|
3789
3946
|
}
|
|
3947
|
+
/**
|
|
3948
|
+
* The source selector a column DECLARED via `sort.selector`, if any — what the
|
|
3949
|
+
* DataSource / array source orders by in place of the field. Resolved like
|
|
3950
|
+
* `declaredSortIndex`: central `props.th` config first, then the element's own
|
|
3951
|
+
* `:sort.prop`. A blank string counts as not declared.
|
|
3952
|
+
*/
|
|
3953
|
+
function declaredSortSelector(field) {
|
|
3954
|
+
const sel = declaredSortConfig(field).selector;
|
|
3955
|
+
return typeof sel === "string" && sel.trim() ? sel.trim() : void 0;
|
|
3956
|
+
}
|
|
3957
|
+
/**
|
|
3958
|
+
* A column's declared sort OBJECT — the element's `:sort.prop` with central
|
|
3959
|
+
* `props.th` config merged over it (props win key by key, as everywhere). `{}`
|
|
3960
|
+
* for `sort: true` / no config.
|
|
3961
|
+
*/
|
|
3962
|
+
function declaredSortConfig(field) {
|
|
3963
|
+
const asObj = (sort) => typeof sort === "object" && sort ? sort : {};
|
|
3964
|
+
let fromEl = {};
|
|
3965
|
+
for (const el of columnEls) if (el.field === field && typeof el.sort === "object" && el.sort) {
|
|
3966
|
+
fromEl = asObj(el.sort);
|
|
3967
|
+
break;
|
|
3968
|
+
}
|
|
3969
|
+
return {
|
|
3970
|
+
...fromEl,
|
|
3971
|
+
...asObj((elementProps.th ?? []).find((c) => c?.field === field)?.sort)
|
|
3972
|
+
};
|
|
3973
|
+
}
|
|
3974
|
+
/**
|
|
3975
|
+
* Whether a sorted column is sorted IN THE BROWSER — its selector fans out over a
|
|
3976
|
+
* collection (`[*]`, which no source can order by) or it declares an `aggregate`.
|
|
3977
|
+
*/
|
|
3978
|
+
function isBrowserSortKey(field) {
|
|
3979
|
+
const sel = declaredSortSelector(field);
|
|
3980
|
+
return !!sel && parseFieldPath(sel).hasWildcard || !!declaredSortConfig(field).aggregate;
|
|
3981
|
+
}
|
|
3790
3982
|
/** Keep the single-value mirrors pointing at the primary key. */
|
|
3791
3983
|
function syncPrimarySort() {
|
|
3792
3984
|
ctrl.sortField = ctrl.sorts[0]?.field ?? null;
|
|
@@ -3975,6 +4167,11 @@ function monoDataGrid(ds = null, opts = {}) {
|
|
|
3975
4167
|
* see the intermediate full-list state.
|
|
3976
4168
|
*/
|
|
3977
4169
|
async function getData() {
|
|
4170
|
+
if (browserRows && browserSortActive()) return [...browserRows];
|
|
4171
|
+
return readAllFromSource();
|
|
4172
|
+
}
|
|
4173
|
+
/** `getData`'s read — every matching row from the source, in its own order. */
|
|
4174
|
+
async function readAllFromSource() {
|
|
3978
4175
|
const s = bound;
|
|
3979
4176
|
if (!s) return [];
|
|
3980
4177
|
const loadOptions = {};
|
|
@@ -110,6 +110,8 @@ export interface MonoSetSortOptions {
|
|
|
110
110
|
*/
|
|
111
111
|
sticky?: boolean;
|
|
112
112
|
}
|
|
113
|
+
/** How a browser-sorted column reduces a row's `[*]` matches — see `MonoColumnSort.aggregate`. */
|
|
114
|
+
export type MonoSortAggregate = 'sum' | 'min' | 'max' | 'avg' | 'count';
|
|
113
115
|
export interface MonoColumnSort {
|
|
114
116
|
/**
|
|
115
117
|
* Whether the column is sortable at all. Defaults to `true` when a `sort` object
|
|
@@ -138,6 +140,40 @@ export interface MonoColumnSort {
|
|
|
138
140
|
index?: number;
|
|
139
141
|
/** Cycle `asc ↔ desc` only (never clears). */
|
|
140
142
|
noClear?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* What the SOURCE sorts by when this column is sorted — instead of the column's
|
|
145
|
+
* `field`. The column keeps its identity (`field`: the arrow, precedence badge,
|
|
146
|
+
* `sorts`, `setSort(field)` and the header menu all still name it); only the
|
|
147
|
+
* selector handed to the DataSource / array source changes.
|
|
148
|
+
*
|
|
149
|
+
* For a column whose `field` is not a property the server knows — a value
|
|
150
|
+
* derived in the browser (`_Total`), or one whose display field differs from
|
|
151
|
+
* the one to order by — point it at one that is: a plain property
|
|
152
|
+
* (`'TotalBudget'`) or a navigation path (`'Brand.Nama'` → `$orderby=Brand/Nama`
|
|
153
|
+
* on a remote source, resolved per row on an array source).
|
|
154
|
+
*
|
|
155
|
+
* A plain selector must be something the source can order by. A selector with a
|
|
156
|
+
* `[*]` WILDCARD — `'Lines.[*].Amount'` — is the one OData cannot (no `$orderby`
|
|
157
|
+
* over a child collection), so it is sorted IN THE BROWSER instead: while such a
|
|
158
|
+
* column is sorted, the grid reads every row the current filter / search matches
|
|
159
|
+
* (with the source's `expand`), reduces each row's matches with `aggregate`
|
|
160
|
+
* (default `'sum'`), sorts, and pages in memory — see `aggregate` / `maxRows`.
|
|
161
|
+
* Flat paged tables only (not grouped, not scroll modes).
|
|
162
|
+
*/
|
|
163
|
+
selector?: string;
|
|
164
|
+
/**
|
|
165
|
+
* How a browser-sorted column (a `[*]` `selector`, or any `selector` when this
|
|
166
|
+
* is set) reduces a row's matches to the value it sorts by. Default `'sum'`.
|
|
167
|
+
* Non-numeric matches are skipped by `sum` / `min` / `max` / `avg`; `count`
|
|
168
|
+
* counts every match.
|
|
169
|
+
*/
|
|
170
|
+
aggregate?: MonoSortAggregate;
|
|
171
|
+
/**
|
|
172
|
+
* Browser-sorted columns only: the most rows the grid will read to sort. Above
|
|
173
|
+
* it the sort is refused (cleared, with a console warning) instead of pulling
|
|
174
|
+
* the whole table. Default `5000`.
|
|
175
|
+
*/
|
|
176
|
+
maxRows?: number;
|
|
141
177
|
/** Sortable UI is shown but inert. */
|
|
142
178
|
disabled?: boolean;
|
|
143
179
|
/**
|