@stonecrop/atable 0.31.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/index.css +804 -1
- package/dist/atable.js +2809 -1944
- package/dist/atable.js.map +1 -1
- package/dist/src/components/ACell.vue.d.ts +17 -0
- package/dist/src/components/ACell.vue.d.ts.map +1 -0
- package/dist/src/components/AGanttCell.vue.d.ts +34 -0
- package/dist/src/components/AGanttCell.vue.d.ts.map +1 -0
- package/dist/src/components/AGanttConnection.vue.d.ts +13 -0
- package/dist/src/components/AGanttConnection.vue.d.ts.map +1 -0
- package/dist/src/components/ARow.vue.d.ts +2693 -0
- package/dist/src/components/ARow.vue.d.ts.map +1 -0
- package/dist/src/components/ARowActions.vue.d.ts +16 -0
- package/dist/src/components/ARowActions.vue.d.ts.map +1 -0
- package/dist/src/components/ATable.vue.d.ts +13358 -0
- package/dist/src/components/ATable.vue.d.ts.map +1 -0
- package/dist/src/components/ATableColumnFilter.vue.d.ts +11 -0
- package/dist/src/components/ATableColumnFilter.vue.d.ts.map +1 -0
- package/dist/src/components/ATableHeader.vue.d.ts +20 -0
- package/dist/src/components/ATableHeader.vue.d.ts.map +1 -0
- package/dist/src/components/ATableLoading.vue.d.ts +14 -0
- package/dist/src/components/ATableLoading.vue.d.ts.map +1 -0
- package/dist/src/components/ATableLoadingBar.vue.d.ts +14 -0
- package/dist/src/components/ATableLoadingBar.vue.d.ts.map +1 -0
- package/dist/src/components/ATableModal.vue.d.ts +18 -0
- package/dist/src/components/ATableModal.vue.d.ts.map +1 -0
- package/dist/src/components/ATablePaginationFooter.vue.d.ts +17 -0
- package/dist/src/components/ATablePaginationFooter.vue.d.ts.map +1 -0
- package/dist/src/icons/index.d.ts +14 -7
- package/dist/src/icons/index.d.ts.map +1 -1
- package/dist/{tsdoc-metadata.json → src/tsdoc-metadata.json} +1 -1
- package/dist/src/types/index.d.ts.map +1 -1
- package/package.json +35 -29
- package/dist/atable.d.ts +0 -3560
- package/dist/atable.tsbuildinfo +0 -1
- package/dist/icons/stonecrop-ui-icon-add.svg +0 -5
- package/dist/icons/stonecrop-ui-icon-delete.svg +0 -5
- package/dist/icons/stonecrop-ui-icon-duplicate.svg +0 -5
- package/dist/icons/stonecrop-ui-icon-insert-above.svg +0 -15
- package/dist/icons/stonecrop-ui-icon-insert-below.svg +0 -15
- package/dist/icons/stonecrop-ui-icon-move.svg +0 -4
- package/dist/icons/stonecrop-ui-icon-open.svg +0 -5
- package/dist/src/composables/table-pagination.js +0 -108
- package/dist/src/icons/index.js +0 -32
- package/dist/src/index.js +0 -33
- package/dist/src/linkSearchableText.js +0 -44
- package/dist/src/resolveFilterType.js +0 -27
- package/dist/src/schemaToColumns.js +0 -59
- package/dist/src/stores/table.js +0 -833
- package/dist/src/types/index.js +0 -0
- package/dist/src/utils.js +0 -39
- package/src/components/ACell.vue +0 -410
- package/src/components/AGanttCell.vue +0 -638
- package/src/components/AGanttConnection.vue +0 -164
- package/src/components/ARow.vue +0 -251
- package/src/components/ARowActions.vue +0 -407
- package/src/components/ATable.vue +0 -538
- package/src/components/ATableColumnFilter.vue +0 -216
- package/src/components/ATableHeader.vue +0 -141
- package/src/components/ATableLoading.vue +0 -86
- package/src/components/ATableLoadingBar.vue +0 -81
- package/src/components/ATableModal.vue +0 -52
- package/src/components/ATablePaginationFooter.vue +0 -100
- package/src/composables/table-pagination.ts +0 -172
- package/src/icons/index.ts +0 -38
- package/src/icons/stonecrop-ui-icon-add.svg +0 -5
- package/src/icons/stonecrop-ui-icon-delete.svg +0 -5
- package/src/icons/stonecrop-ui-icon-duplicate.svg +0 -5
- package/src/icons/stonecrop-ui-icon-insert-above.svg +0 -15
- package/src/icons/stonecrop-ui-icon-insert-below.svg +0 -15
- package/src/icons/stonecrop-ui-icon-move.svg +0 -4
- package/src/icons/stonecrop-ui-icon-open.svg +0 -5
- package/src/index.ts +0 -62
- package/src/linkSearchableText.ts +0 -42
- package/src/resolveFilterType.ts +0 -32
- package/src/schemaToColumns.ts +0 -67
- package/src/shims-vue.d.ts +0 -10
- package/src/stores/table.ts +0 -978
- package/src/types/index.ts +0 -794
- package/src/utils.ts +0 -40
package/dist/atable.js
CHANGED
|
@@ -1,1958 +1,2823 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { defaultKeypressHandlers
|
|
3
|
-
import { componentCategory
|
|
4
|
-
import {
|
|
5
|
-
import { defineStore
|
|
6
|
-
import {
|
|
7
|
-
import './assets/index.css'
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, inject, mergeModels, mergeProps, nextTick, normalizeClass, normalizeProps, normalizeStyle, onMounted, onUnmounted, openBlock, reactive, ref, renderList, renderSlot, resolveDynamicComponent, toDisplayString, toValue, unref, useCssVars, useModel, useTemplateRef, vModelCheckbox, vModelSelect, vModelText, vShow, watch, withCtx, withDirectives, withModifiers } from "vue";
|
|
2
|
+
import { defaultKeypressHandlers, useKeyboardNav } from "@stonecrop/utilities";
|
|
3
|
+
import { componentCategory, hasBadgeOptions, isBadgeDescriptor } from "@stonecrop/schema";
|
|
4
|
+
import { onClickOutside, useDebounceFn, useDraggable, useElementBounding, useMutationObserver, useResizeObserver } from "@vueuse/core";
|
|
5
|
+
import { defineStore } from "pinia";
|
|
6
|
+
import { vOnClickOutside, vResizeObserver } from "@vueuse/components";
|
|
7
|
+
import './assets/index.css';//#region src/linkSearchableText.ts
|
|
8
|
+
/**
|
|
9
|
+
* Normalize a scalar cell value to a non-empty string, or nothing.
|
|
10
|
+
*
|
|
11
|
+
* Rejecting objects is what the haystack wants: a nested value has no single textual form, and
|
|
12
|
+
* `String()` on one contributes `[object Object]`, which matches a search for "object" and nothing
|
|
13
|
+
* a user would actually type.
|
|
14
|
+
*/
|
|
15
|
+
function scalarText(value) {
|
|
16
|
+
if (value == null || typeof value === "object") return void 0;
|
|
17
|
+
if (typeof value === "string") return value === "" ? void 0 : value;
|
|
18
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
|
|
13
19
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Build the substring-search haystack for a link column cell.
|
|
22
|
+
* Server middleware enriches inline FKs to `{ id, displayText }`; search both.
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
function linkSearchableText(cellValue) {
|
|
26
|
+
if (cellValue == null || cellValue === "") return "";
|
|
27
|
+
if (typeof cellValue === "object") {
|
|
28
|
+
const parts = [];
|
|
29
|
+
if ("id" in cellValue) {
|
|
30
|
+
const id = scalarText(cellValue.id);
|
|
31
|
+
if (id !== void 0) parts.push(id);
|
|
32
|
+
}
|
|
33
|
+
if ("displayText" in cellValue) {
|
|
34
|
+
const displayText = scalarText(cellValue.displayText);
|
|
35
|
+
if (displayText !== void 0) parts.push(displayText);
|
|
36
|
+
}
|
|
37
|
+
return parts.join(" ");
|
|
38
|
+
}
|
|
39
|
+
return scalarText(cellValue) ?? "";
|
|
29
40
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
//#endregion
|
|
42
|
+
//#region src/resolveFilterType.ts
|
|
43
|
+
var CATEGORY_FILTER = {
|
|
44
|
+
text: "text",
|
|
45
|
+
number: "number",
|
|
46
|
+
boolean: "checkbox",
|
|
47
|
+
date: "date",
|
|
48
|
+
datetime: "dateRange",
|
|
49
|
+
select: "select",
|
|
50
|
+
code: "text",
|
|
51
|
+
link: "text",
|
|
52
|
+
attach: "text",
|
|
53
|
+
quantity: "number",
|
|
54
|
+
currency: "number"
|
|
42
55
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Resolve the filter widget and filter logic type for a column.
|
|
58
|
+
* Explicit `filterType` wins; otherwise derive from the component category.
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
function resolveFilterType(column) {
|
|
62
|
+
if (column.filterType) return column.filterType;
|
|
63
|
+
const category = componentCategory(column.component);
|
|
64
|
+
if (category) return CATEGORY_FILTER[category];
|
|
65
|
+
return "text";
|
|
47
66
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (typeof e == "object") {
|
|
54
|
-
const a = e.qty ?? "", i = e.uom ?? "";
|
|
55
|
-
return i ? `${a} ${i}`.trim() : String(a);
|
|
56
|
-
}
|
|
57
|
-
return String(e);
|
|
58
|
-
}, ot = (e) => {
|
|
59
|
-
if (e == null) return "";
|
|
60
|
-
if (typeof e == "object") {
|
|
61
|
-
const a = e.amount ?? "", i = e.currency?.displayText ?? e.currency?.id ?? "";
|
|
62
|
-
return i ? `${a} ${i}`.trim() : String(a);
|
|
63
|
-
}
|
|
64
|
-
return String(e);
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/utils.ts
|
|
69
|
+
var isHtmlString = (htmlString) => {
|
|
70
|
+
const $document = new DOMParser().parseFromString(htmlString, "text/html");
|
|
71
|
+
return Array.from($document.body.childNodes).some((node) => node.nodeType === 1);
|
|
65
72
|
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
var generateHash = (length = 8) => {
|
|
74
|
+
return Array.from({ length }, () => Math.floor(Math.random() * 16).toString(16)).join("");
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Render a composite quantity value (`{ qty, uom }`, see `QuantityValue` in `@stonecrop/aform`)
|
|
78
|
+
* as `"<qty> <uom>"`. Shared by the two paths a quantity column can reach formatting through:
|
|
79
|
+
* the `format` that `schemaToColumns` attaches, and the table store's category-based default.
|
|
80
|
+
*/
|
|
81
|
+
var formatQuantity = (value) => {
|
|
82
|
+
if (value === null || value === void 0) return "";
|
|
83
|
+
if (typeof value === "object") {
|
|
84
|
+
const qty = value.qty ?? "";
|
|
85
|
+
const uom = value.uom ?? "";
|
|
86
|
+
return uom ? `${qty} ${uom}`.trim() : String(qty);
|
|
87
|
+
}
|
|
88
|
+
return String(value);
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Render a composite currency value (`{ amount, currency }`, see `CurrencyValue` in
|
|
92
|
+
* `@stonecrop/aform`) as `"<amount> <currency>"`. `currency` is an AFormLinkValue FK reference —
|
|
93
|
+
* its `displayText` is preferred, falling back to `id`. Shared by the two paths a currency column
|
|
94
|
+
* can reach formatting through: the `format` that `schemaToColumns` attaches, and the table
|
|
95
|
+
* store's category-based default.
|
|
96
|
+
*/
|
|
97
|
+
var formatCurrency = (value) => {
|
|
98
|
+
if (value === null || value === void 0) return "";
|
|
99
|
+
if (typeof value === "object") {
|
|
100
|
+
const amount = value.amount ?? "";
|
|
101
|
+
const currency = value.currency?.displayText ?? value.currency?.id ?? "";
|
|
102
|
+
return currency ? `${amount} ${currency}`.trim() : String(amount);
|
|
103
|
+
}
|
|
104
|
+
return String(value);
|
|
105
|
+
};
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/stores/table.ts
|
|
108
|
+
function toComparableNumber(cellValue) {
|
|
109
|
+
if (cellValue !== null && typeof cellValue === "object") {
|
|
110
|
+
if ("qty" in cellValue) return Number(cellValue.qty);
|
|
111
|
+
if ("baseAmount" in cellValue && cellValue.baseAmount != null) return Number(cellValue.baseAmount);
|
|
112
|
+
if ("amount" in cellValue) return Number(cellValue.amount);
|
|
113
|
+
}
|
|
114
|
+
return Number(cellValue);
|
|
74
115
|
}
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
116
|
+
function isNodeOpen(rowIndex, treeDisplay) {
|
|
117
|
+
const row = treeDisplay[rowIndex];
|
|
118
|
+
if (row.isRoot) return true;
|
|
119
|
+
if (row.parent === null || row.parent === void 0) return true;
|
|
120
|
+
const parentIndex = row.parent;
|
|
121
|
+
if (parentIndex < 0 || parentIndex >= treeDisplay.length) return false;
|
|
122
|
+
return (treeDisplay[parentIndex].childrenOpen || false) && isNodeOpen(parentIndex, treeDisplay);
|
|
81
123
|
}
|
|
82
|
-
function
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
124
|
+
function applyFilter(cellValue, filter, column) {
|
|
125
|
+
const filterType = resolveFilterType(column);
|
|
126
|
+
const value = filter.value;
|
|
127
|
+
if (!value && filterType !== "dateRange" && filterType !== "checkbox") return true;
|
|
128
|
+
switch (filterType) {
|
|
129
|
+
case "text": return (column.linkDoctype ? linkSearchableText(cellValue) : typeof cellValue === "object" && cellValue !== null ? Object.values(cellValue).join(" ") : String(cellValue || "")).toLowerCase().includes(String(value).toLowerCase());
|
|
130
|
+
case "number": {
|
|
131
|
+
const numValue = toComparableNumber(cellValue);
|
|
132
|
+
const filterNum = Number(value);
|
|
133
|
+
return !isNaN(numValue) && !isNaN(filterNum) && numValue === filterNum;
|
|
134
|
+
}
|
|
135
|
+
case "select": return cellValue === value;
|
|
136
|
+
case "checkbox":
|
|
137
|
+
if (value === true) return !!cellValue;
|
|
138
|
+
return true;
|
|
139
|
+
case "date": {
|
|
140
|
+
let cellDate;
|
|
141
|
+
if (typeof cellValue === "number") {
|
|
142
|
+
const originalDate = new Date(cellValue);
|
|
143
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
144
|
+
cellDate = new Date(currentYear, originalDate.getMonth(), originalDate.getDate());
|
|
145
|
+
} else cellDate = new Date(String(cellValue));
|
|
146
|
+
const filterDate = new Date(String(value));
|
|
147
|
+
return cellDate.toDateString() === filterDate.toDateString();
|
|
148
|
+
}
|
|
149
|
+
case "dateRange": {
|
|
150
|
+
const startValue = filter.startValue;
|
|
151
|
+
const endValue = filter.endValue;
|
|
152
|
+
if (!startValue && !endValue) return true;
|
|
153
|
+
let cellDateRange;
|
|
154
|
+
if (typeof cellValue === "number") {
|
|
155
|
+
const originalDate = new Date(cellValue);
|
|
156
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
157
|
+
cellDateRange = new Date(currentYear, originalDate.getMonth(), originalDate.getDate());
|
|
158
|
+
} else cellDateRange = new Date(String(cellValue));
|
|
159
|
+
if (startValue && cellDateRange < new Date(String(startValue))) return false;
|
|
160
|
+
if (endValue && cellDateRange > new Date(String(endValue))) return false;
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
default: return true;
|
|
164
|
+
}
|
|
120
165
|
}
|
|
121
|
-
|
|
122
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Compute the CSS indentation for a tree-table cell. Pure helper (captures no store state);
|
|
168
|
+
* imported directly by cell components rather than exposed on the store's public return.
|
|
169
|
+
* @internal
|
|
170
|
+
*/
|
|
171
|
+
function getIndent(colIndex, indentLevel) {
|
|
172
|
+
if (indentLevel && colIndex === 0 && indentLevel > 0) return `${indentLevel}ch`;
|
|
173
|
+
else return "inherit";
|
|
123
174
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
},
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
},
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
}
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
175
|
+
/**
|
|
176
|
+
* Create a table store
|
|
177
|
+
* @param initData - Initial data for the table store
|
|
178
|
+
* @returns table store instance
|
|
179
|
+
* @public
|
|
180
|
+
*/
|
|
181
|
+
var createTableStore = (initData) => {
|
|
182
|
+
const id = initData.id || generateHash();
|
|
183
|
+
const linkResolver = initData.linkResolver ?? null;
|
|
184
|
+
return defineStore(`table-${id}`, () => {
|
|
185
|
+
const createDisplayObject = () => {
|
|
186
|
+
const defaultDisplay = [Object.assign({}, { rowModified: false })];
|
|
187
|
+
const parents = /* @__PURE__ */ new Set();
|
|
188
|
+
for (let rowIndex = 0; rowIndex < rows.value.length; rowIndex++) {
|
|
189
|
+
const row = rows.value[rowIndex];
|
|
190
|
+
if (row.parent !== null && row.parent !== void 0) parents.add(row.parent);
|
|
191
|
+
}
|
|
192
|
+
const hasGanttData = (rowIndex) => {
|
|
193
|
+
return rows.value[rowIndex]?.gantt !== void 0;
|
|
194
|
+
};
|
|
195
|
+
const hasGanttDescendant = (rowIndex) => {
|
|
196
|
+
for (let i = 0; i < rows.value.length; i++) if (rows.value[i].parent === rowIndex) {
|
|
197
|
+
if (hasGanttData(i) || hasGanttDescendant(i)) return true;
|
|
198
|
+
}
|
|
199
|
+
return false;
|
|
200
|
+
};
|
|
201
|
+
const shouldChildrenBeOpen = (rowIndex) => {
|
|
202
|
+
const currentConfig = config.value;
|
|
203
|
+
const expansionMode = currentConfig.view === "tree" || currentConfig.view === "tree-gantt" ? currentConfig.defaultTreeExpansion : void 0;
|
|
204
|
+
if (!expansionMode) return true;
|
|
205
|
+
switch (expansionMode) {
|
|
206
|
+
case "root": return false;
|
|
207
|
+
case "branch": return hasGanttDescendant(rowIndex);
|
|
208
|
+
case "leaf": return true;
|
|
209
|
+
default: return true;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
for (let rowIndex = 0; rowIndex < rows.value.length; rowIndex++) {
|
|
213
|
+
const row = rows.value[rowIndex];
|
|
214
|
+
const isRootNode = row.parent === null || row.parent === void 0;
|
|
215
|
+
const isParentNode = parents.has(rowIndex);
|
|
216
|
+
defaultDisplay[rowIndex] = {
|
|
217
|
+
childrenOpen: shouldChildrenBeOpen(rowIndex),
|
|
218
|
+
expanded: false,
|
|
219
|
+
indent: row.indent || 0,
|
|
220
|
+
isParent: isParentNode,
|
|
221
|
+
isRoot: isRootNode,
|
|
222
|
+
rowModified: false,
|
|
223
|
+
open: isRootNode,
|
|
224
|
+
parent: row.parent
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
return defaultDisplay;
|
|
228
|
+
};
|
|
229
|
+
const columns = ref(initData.columns);
|
|
230
|
+
const rows = ref(initData.rows);
|
|
231
|
+
const config = ref(initData.config || {});
|
|
232
|
+
const rowModifications = ref({});
|
|
233
|
+
const rowExpandStates = ref({});
|
|
234
|
+
const table = computed(() => {
|
|
235
|
+
const tableData = {};
|
|
236
|
+
for (const [colIndex, column] of columns.value.entries()) for (const [rowIndex, row] of rows.value.entries()) tableData[`${colIndex}:${rowIndex}`] = row[column.name];
|
|
237
|
+
return tableData;
|
|
238
|
+
});
|
|
239
|
+
const display = computed({
|
|
240
|
+
get: () => {
|
|
241
|
+
const baseDisplay = createDisplayObject();
|
|
242
|
+
for (let i = 0; i < baseDisplay.length; i++) {
|
|
243
|
+
if (rowModifications.value[i]) baseDisplay[i].rowModified = rowModifications.value[i];
|
|
244
|
+
if (rowExpandStates.value[i]) {
|
|
245
|
+
if (rowExpandStates.value[i].childrenOpen !== void 0) baseDisplay[i].childrenOpen = rowExpandStates.value[i].childrenOpen;
|
|
246
|
+
if (rowExpandStates.value[i].expanded !== void 0) baseDisplay[i].expanded = rowExpandStates.value[i].expanded;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
if (isTreeView.value) {
|
|
250
|
+
for (let i = 0; i < baseDisplay.length; i++) if (!baseDisplay[i].isRoot) baseDisplay[i].open = isNodeOpen(i, baseDisplay);
|
|
251
|
+
}
|
|
252
|
+
return baseDisplay;
|
|
253
|
+
},
|
|
254
|
+
set: (newDisplay) => {
|
|
255
|
+
if (JSON.stringify(newDisplay) !== JSON.stringify(display.value)) display.value = newDisplay;
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
const modal = ref(initData.modal || { visible: false });
|
|
259
|
+
const updates = ref({});
|
|
260
|
+
const ganttBars = ref([]);
|
|
261
|
+
const connectionHandles = ref([]);
|
|
262
|
+
const connectionPaths = ref([]);
|
|
263
|
+
const sortState = ref({
|
|
264
|
+
column: null,
|
|
265
|
+
direction: null
|
|
266
|
+
});
|
|
267
|
+
const filterState = ref({});
|
|
268
|
+
const hasPinnedColumns = computed(() => columns.value.some((col) => col.pinned));
|
|
269
|
+
const isGanttView = computed(() => config.value.view === "gantt" || config.value.view === "tree-gantt");
|
|
270
|
+
const isTreeView = computed(() => config.value.view === "tree" || config.value.view === "tree-gantt");
|
|
271
|
+
const isDependencyGraphEnabled = computed(() => {
|
|
272
|
+
const currentConfig = config.value;
|
|
273
|
+
return currentConfig.view === "gantt" || currentConfig.view === "tree-gantt" ? currentConfig.dependencyGraph !== false : true;
|
|
274
|
+
});
|
|
275
|
+
const numberedRowWidth = computed(() => {
|
|
276
|
+
return `${Math.ceil(rows.value.length / 100 + 1)}ch`;
|
|
277
|
+
});
|
|
278
|
+
const zeroColumn = computed(() => config.value.view ? [
|
|
279
|
+
"list",
|
|
280
|
+
"tree",
|
|
281
|
+
"tree-gantt",
|
|
282
|
+
"list-expansion"
|
|
283
|
+
].includes(config.value.view) : false);
|
|
284
|
+
const filteredRows = computed(() => {
|
|
285
|
+
let filtered = rows.value.map((row, originalIndex) => ({
|
|
286
|
+
...row,
|
|
287
|
+
originalIndex
|
|
288
|
+
}));
|
|
289
|
+
Object.entries(filterState.value).forEach(([colIndexStr, filter]) => {
|
|
290
|
+
const colIndex = parseInt(colIndexStr);
|
|
291
|
+
const column = columns.value[colIndex];
|
|
292
|
+
if (!column) return;
|
|
293
|
+
if (!(filter.value || filter.startValue || filter.endValue || resolveFilterType(column) === "checkbox" && filter.value !== void 0)) return;
|
|
294
|
+
filtered = filtered.filter((row) => {
|
|
295
|
+
const cellValue = row[column.name];
|
|
296
|
+
return applyFilter(cellValue, filter, column);
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
if (sortState.value.column !== null && sortState.value.direction) {
|
|
300
|
+
const column = columns.value[sortState.value.column];
|
|
301
|
+
const direction = sortState.value.direction;
|
|
302
|
+
filtered.sort((a, b) => {
|
|
303
|
+
let aVal = a[column.name];
|
|
304
|
+
let bVal = b[column.name];
|
|
305
|
+
if (aVal === null || aVal === void 0) aVal = "";
|
|
306
|
+
if (bVal === null || bVal === void 0) bVal = "";
|
|
307
|
+
const aNum = toComparableNumber(aVal);
|
|
308
|
+
const bNum = toComparableNumber(bVal);
|
|
309
|
+
if (!isNaN(aNum) && !isNaN(bNum) && aVal !== "" && bVal !== "") return direction === "asc" ? aNum - bNum : bNum - aNum;
|
|
310
|
+
else {
|
|
311
|
+
const aStr = String(aVal).toLowerCase();
|
|
312
|
+
const bStr = String(bVal).toLowerCase();
|
|
313
|
+
return direction === "asc" ? aStr.localeCompare(bStr) : bStr.localeCompare(aStr);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
return filtered;
|
|
318
|
+
});
|
|
319
|
+
const getCellData = (colIndex, rowIndex) => table.value[`${colIndex}:${rowIndex}`];
|
|
320
|
+
const setCellData = (colIndex, rowIndex, value) => {
|
|
321
|
+
const index = `${colIndex}:${rowIndex}`;
|
|
322
|
+
const col = columns.value[colIndex];
|
|
323
|
+
if (table.value[index] !== value) rowModifications.value[rowIndex] = true;
|
|
324
|
+
table.value[index] = value;
|
|
325
|
+
rows.value[rowIndex] = {
|
|
326
|
+
...rows.value[rowIndex],
|
|
327
|
+
[col.name]: value
|
|
328
|
+
};
|
|
329
|
+
};
|
|
330
|
+
const updateRows = (newRows) => {
|
|
331
|
+
rows.value = newRows;
|
|
332
|
+
};
|
|
333
|
+
const setCellText = (colIndex, rowIndex, value) => {
|
|
334
|
+
const index = `${colIndex}:${rowIndex}`;
|
|
335
|
+
if (table.value[index] !== value) {
|
|
336
|
+
rowModifications.value[rowIndex] = true;
|
|
337
|
+
updates.value[index] = value;
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
const getHeaderCellStyle = (column) => {
|
|
341
|
+
const isLastCol = columns.value.indexOf(column) === columns.value.length - 1;
|
|
342
|
+
const isResizable = config.value.fullWidth ? column.resizable && !isLastCol : column.resizable;
|
|
343
|
+
return {
|
|
344
|
+
width: column.width || "40ch",
|
|
345
|
+
textAlign: column.align || "center",
|
|
346
|
+
...isResizable && {
|
|
347
|
+
resize: "horizontal",
|
|
348
|
+
overflow: "hidden",
|
|
349
|
+
whiteSpace: "nowrap"
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
};
|
|
353
|
+
const resizeColumn = (colIndex, newWidth) => {
|
|
354
|
+
if (colIndex < 0 || colIndex >= columns.value.length) return;
|
|
355
|
+
const finalWidth = Math.max(newWidth, 40);
|
|
356
|
+
columns.value[colIndex] = {
|
|
357
|
+
...columns.value[colIndex],
|
|
358
|
+
width: `${finalWidth}px`
|
|
359
|
+
};
|
|
360
|
+
};
|
|
361
|
+
const isRowGantt = (rowIndex) => {
|
|
362
|
+
const row = rows.value[rowIndex];
|
|
363
|
+
return isGanttView.value && row.gantt !== void 0;
|
|
364
|
+
};
|
|
365
|
+
const isRowVisible = (rowIndex) => {
|
|
366
|
+
return !isTreeView.value || display.value[rowIndex].isRoot || display.value[rowIndex].open;
|
|
367
|
+
};
|
|
368
|
+
const getRowExpandSymbol = (rowIndex) => {
|
|
369
|
+
if (!isTreeView.value && config.value.view !== "list-expansion") return "";
|
|
370
|
+
if (isTreeView.value && (display.value[rowIndex].isRoot || display.value[rowIndex].isParent)) return display.value[rowIndex].childrenOpen ? "▼" : "►";
|
|
371
|
+
if (config.value.view === "list-expansion") return display.value[rowIndex].expanded ? "▼" : "►";
|
|
372
|
+
return "";
|
|
373
|
+
};
|
|
374
|
+
const toggleRowExpand = (rowIndex) => {
|
|
375
|
+
if (isTreeView.value) {
|
|
376
|
+
const currentState = rowExpandStates.value[rowIndex] || {};
|
|
377
|
+
const newChildrenOpen = !(currentState.childrenOpen ?? display.value[rowIndex].childrenOpen);
|
|
378
|
+
rowExpandStates.value[rowIndex] = {
|
|
379
|
+
...currentState,
|
|
380
|
+
childrenOpen: newChildrenOpen
|
|
381
|
+
};
|
|
382
|
+
if (!newChildrenOpen) closeDescendants(rowIndex);
|
|
383
|
+
} else if (config.value.view === "list-expansion") {
|
|
384
|
+
const currentState = rowExpandStates.value[rowIndex] || {};
|
|
385
|
+
const currentExpanded = currentState.expanded ?? display.value[rowIndex].expanded;
|
|
386
|
+
rowExpandStates.value[rowIndex] = {
|
|
387
|
+
...currentState,
|
|
388
|
+
expanded: !currentExpanded
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
const closeDescendants = (parentRowIndex) => {
|
|
393
|
+
for (let index = 0; index < rows.value.length; index++) if (display.value[index].parent === parentRowIndex) {
|
|
394
|
+
const childState = rowExpandStates.value[index] || {};
|
|
395
|
+
rowExpandStates.value[index] = {
|
|
396
|
+
...childState,
|
|
397
|
+
childrenOpen: false
|
|
398
|
+
};
|
|
399
|
+
closeDescendants(index);
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
const getCellDisplayValue = (colIndex, rowIndex) => {
|
|
403
|
+
const cellData = getCellData(colIndex, rowIndex);
|
|
404
|
+
return getFormattedValue(colIndex, rowIndex, cellData);
|
|
405
|
+
};
|
|
406
|
+
const getFormattedValue = (colIndex, rowIndex, value) => {
|
|
407
|
+
const column = columns.value[colIndex];
|
|
408
|
+
const row = rows.value[rowIndex];
|
|
409
|
+
const format = column.format;
|
|
410
|
+
if (!format) {
|
|
411
|
+
const category = componentCategory(column.component);
|
|
412
|
+
if (category === "boolean") return value ? "✓" : "✗";
|
|
413
|
+
if (category === "date") return value != null ? new Date(String(value)).toLocaleDateString() : value;
|
|
414
|
+
if (category === "datetime") return value != null ? new Date(String(value)).toLocaleString() : value;
|
|
415
|
+
if (category === "quantity") return formatQuantity(value);
|
|
416
|
+
if (category === "currency") return formatCurrency(value);
|
|
417
|
+
return value;
|
|
418
|
+
}
|
|
419
|
+
if (typeof format === "function") return format(value, {
|
|
420
|
+
table: table.value,
|
|
421
|
+
row,
|
|
422
|
+
column
|
|
423
|
+
});
|
|
424
|
+
else if (typeof format === "string") return Function(`"use strict";return (${format})`)()(value, {
|
|
425
|
+
table: table.value,
|
|
426
|
+
row,
|
|
427
|
+
column
|
|
428
|
+
});
|
|
429
|
+
return value;
|
|
430
|
+
};
|
|
431
|
+
const closeModal = (event) => {
|
|
432
|
+
if (!(event.target instanceof Node)) {
|
|
433
|
+
if (modal.value.visible) modal.value.visible = false;
|
|
434
|
+
} else if (!modal.value.parent?.contains(event.target)) {
|
|
435
|
+
if (modal.value.visible) modal.value.visible = false;
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
const updateGanttBar = (event) => {
|
|
439
|
+
const ganttBar = rows.value[event.rowIndex]?.gantt;
|
|
440
|
+
if (ganttBar) {
|
|
441
|
+
if (event.type === "resize") {
|
|
442
|
+
if (event.edge === "start") {
|
|
443
|
+
ganttBar.startIndex = event.newStart;
|
|
444
|
+
ganttBar.endIndex = event.end;
|
|
445
|
+
ganttBar.colspan = ganttBar.endIndex - ganttBar.startIndex;
|
|
446
|
+
} else if (event.edge === "end") {
|
|
447
|
+
ganttBar.startIndex = event.start;
|
|
448
|
+
ganttBar.endIndex = event.newEnd;
|
|
449
|
+
ganttBar.colspan = ganttBar.endIndex - ganttBar.startIndex;
|
|
450
|
+
}
|
|
451
|
+
} else if (event.type === "bar") {
|
|
452
|
+
ganttBar.startIndex = event.newStart;
|
|
453
|
+
ganttBar.endIndex = event.newEnd;
|
|
454
|
+
ganttBar.colspan = ganttBar.endIndex - ganttBar.startIndex;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
};
|
|
458
|
+
const registerGanttBar = (barInfo) => {
|
|
459
|
+
const existingIndex = ganttBars.value.findIndex((bar) => bar.id === barInfo.id);
|
|
460
|
+
if (existingIndex >= 0) ganttBars.value[existingIndex] = barInfo;
|
|
461
|
+
else ganttBars.value.push(barInfo);
|
|
462
|
+
};
|
|
463
|
+
const unregisterGanttBar = (barId) => {
|
|
464
|
+
const index = ganttBars.value.findIndex((bar) => bar.id === barId);
|
|
465
|
+
if (index >= 0) ganttBars.value.splice(index, 1);
|
|
466
|
+
};
|
|
467
|
+
const registerConnectionHandle = (handleInfo) => {
|
|
468
|
+
const existingIndex = connectionHandles.value.findIndex((handle) => handle.id === handleInfo.id);
|
|
469
|
+
if (existingIndex >= 0) connectionHandles.value[existingIndex] = handleInfo;
|
|
470
|
+
else connectionHandles.value.push(handleInfo);
|
|
471
|
+
};
|
|
472
|
+
const unregisterConnectionHandle = (handleId) => {
|
|
473
|
+
const index = connectionHandles.value.findIndex((handle) => handle.id === handleId);
|
|
474
|
+
if (index >= 0) connectionHandles.value.splice(index, 1);
|
|
475
|
+
};
|
|
476
|
+
const createConnection = (fromHandleId, toHandleId, options) => {
|
|
477
|
+
const fromHandle = connectionHandles.value.find((h) => h.id === fromHandleId);
|
|
478
|
+
const toHandle = connectionHandles.value.find((h) => h.id === toHandleId);
|
|
479
|
+
if (!fromHandle || !toHandle) {
|
|
480
|
+
console.warn("Cannot create connection: handle not found");
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
const connection = {
|
|
484
|
+
id: `connection-${fromHandleId}-${toHandleId}`,
|
|
485
|
+
from: {
|
|
486
|
+
barId: fromHandle.barId,
|
|
487
|
+
side: fromHandle.side
|
|
488
|
+
},
|
|
489
|
+
to: {
|
|
490
|
+
barId: toHandle.barId,
|
|
491
|
+
side: toHandle.side
|
|
492
|
+
},
|
|
493
|
+
style: options?.style,
|
|
494
|
+
label: options?.label
|
|
495
|
+
};
|
|
496
|
+
connectionPaths.value.push(connection);
|
|
497
|
+
return connection;
|
|
498
|
+
};
|
|
499
|
+
const deleteConnection = (connectionId) => {
|
|
500
|
+
const index = connectionPaths.value.findIndex((conn) => conn.id === connectionId);
|
|
501
|
+
if (index >= 0) {
|
|
502
|
+
connectionPaths.value.splice(index, 1);
|
|
503
|
+
return true;
|
|
504
|
+
}
|
|
505
|
+
return false;
|
|
506
|
+
};
|
|
507
|
+
const getConnectionsForBar = (barId) => {
|
|
508
|
+
return connectionPaths.value.filter((conn) => conn.from.barId === barId || conn.to.barId === barId);
|
|
509
|
+
};
|
|
510
|
+
const getHandlesForBar = (barId) => {
|
|
511
|
+
return connectionHandles.value.filter((handle) => handle.barId === barId);
|
|
512
|
+
};
|
|
513
|
+
const sortByColumn = (colIndex) => {
|
|
514
|
+
if (columns.value[colIndex].sortable === false) return;
|
|
515
|
+
let newDirection;
|
|
516
|
+
if (sortState.value.column === colIndex) {
|
|
517
|
+
if (sortState.value.direction === "asc") newDirection = "desc";
|
|
518
|
+
else newDirection = "asc";
|
|
519
|
+
} else newDirection = "asc";
|
|
520
|
+
sortState.value.column = colIndex;
|
|
521
|
+
sortState.value.direction = newDirection;
|
|
522
|
+
};
|
|
523
|
+
const setFilter = (colIndex, filter) => {
|
|
524
|
+
if (!filter.value && !filter.startValue && !filter.endValue) delete filterState.value[colIndex];
|
|
525
|
+
else filterState.value[colIndex] = filter;
|
|
526
|
+
};
|
|
527
|
+
const clearFilter = (colIndex) => {
|
|
528
|
+
delete filterState.value[colIndex];
|
|
529
|
+
};
|
|
530
|
+
/**
|
|
531
|
+
* Add a new row to the table.
|
|
532
|
+
* @param rowData - Optional partial row data to initialize the new row with
|
|
533
|
+
* @param position - Where to insert the row: 'start', 'end', or a specific index
|
|
534
|
+
* @returns The index of the newly added row
|
|
535
|
+
*/
|
|
536
|
+
const addRow = (rowData, position = "end") => {
|
|
537
|
+
const newRow = {};
|
|
538
|
+
for (const column of columns.value) newRow[column.name] = "";
|
|
539
|
+
if (rowData) Object.assign(newRow, rowData);
|
|
540
|
+
let insertIndex;
|
|
541
|
+
if (position === "start") {
|
|
542
|
+
insertIndex = 0;
|
|
543
|
+
rows.value.unshift(newRow);
|
|
544
|
+
} else if (position === "end") {
|
|
545
|
+
insertIndex = rows.value.length;
|
|
546
|
+
rows.value.push(newRow);
|
|
547
|
+
} else {
|
|
548
|
+
insertIndex = Math.max(0, Math.min(position, rows.value.length));
|
|
549
|
+
rows.value.splice(insertIndex, 0, newRow);
|
|
550
|
+
}
|
|
551
|
+
return insertIndex;
|
|
552
|
+
};
|
|
553
|
+
/**
|
|
554
|
+
* Delete a row from the table.
|
|
555
|
+
* @param rowIndex - The index of the row to delete
|
|
556
|
+
* @returns The deleted row, or null if the index was invalid
|
|
557
|
+
*/
|
|
558
|
+
const deleteRow = (rowIndex) => {
|
|
559
|
+
if (rowIndex < 0 || rowIndex >= rows.value.length) return null;
|
|
560
|
+
const [deletedRow] = rows.value.splice(rowIndex, 1);
|
|
561
|
+
delete rowModifications.value[rowIndex];
|
|
562
|
+
delete rowExpandStates.value[rowIndex];
|
|
563
|
+
const newModifications = {};
|
|
564
|
+
const newExpandStates = {};
|
|
565
|
+
for (const [key, value] of Object.entries(rowModifications.value)) {
|
|
566
|
+
const idx = parseInt(key);
|
|
567
|
+
if (idx > rowIndex) newModifications[idx - 1] = value;
|
|
568
|
+
else newModifications[idx] = value;
|
|
569
|
+
}
|
|
570
|
+
for (const [key, value] of Object.entries(rowExpandStates.value)) {
|
|
571
|
+
const idx = parseInt(key);
|
|
572
|
+
if (idx > rowIndex) newExpandStates[idx - 1] = value;
|
|
573
|
+
else newExpandStates[idx] = value;
|
|
574
|
+
}
|
|
575
|
+
rowModifications.value = newModifications;
|
|
576
|
+
rowExpandStates.value = newExpandStates;
|
|
577
|
+
return deletedRow;
|
|
578
|
+
};
|
|
579
|
+
/**
|
|
580
|
+
* Duplicate a row in the table.
|
|
581
|
+
* @param rowIndex - The index of the row to duplicate
|
|
582
|
+
* @returns The index of the new duplicated row, or -1 if the index was invalid
|
|
583
|
+
*/
|
|
584
|
+
const duplicateRow = (rowIndex) => {
|
|
585
|
+
if (rowIndex < 0 || rowIndex >= rows.value.length) return -1;
|
|
586
|
+
const originalRow = rows.value[rowIndex];
|
|
587
|
+
const duplicatedRow = JSON.parse(JSON.stringify(originalRow));
|
|
588
|
+
const newIndex = rowIndex + 1;
|
|
589
|
+
rows.value.splice(newIndex, 0, duplicatedRow);
|
|
590
|
+
return newIndex;
|
|
591
|
+
};
|
|
592
|
+
/**
|
|
593
|
+
* Insert a new row above the specified row.
|
|
594
|
+
* @param rowIndex - The index of the row to insert above
|
|
595
|
+
* @param rowData - Optional partial row data to initialize the new row with
|
|
596
|
+
* @returns The index of the newly inserted row
|
|
597
|
+
*/
|
|
598
|
+
const insertRowAbove = (rowIndex, rowData) => {
|
|
599
|
+
return addRow(rowData, Math.max(0, rowIndex));
|
|
600
|
+
};
|
|
601
|
+
/**
|
|
602
|
+
* Insert a new row below the specified row.
|
|
603
|
+
* @param rowIndex - The index of the row to insert below
|
|
604
|
+
* @param rowData - Optional partial row data to initialize the new row with
|
|
605
|
+
* @returns The index of the newly inserted row
|
|
606
|
+
*/
|
|
607
|
+
const insertRowBelow = (rowIndex, rowData) => {
|
|
608
|
+
const insertIndex = Math.min(rowIndex + 1, rows.value.length);
|
|
609
|
+
return addRow(rowData, insertIndex);
|
|
610
|
+
};
|
|
611
|
+
/**
|
|
612
|
+
* Move a row from one position to another.
|
|
613
|
+
* @param fromIndex - The current index of the row to move
|
|
614
|
+
* @param toIndex - The target index to move the row to
|
|
615
|
+
* @returns true if the move was successful, false otherwise
|
|
616
|
+
*/
|
|
617
|
+
const moveRow = (fromIndex, toIndex) => {
|
|
618
|
+
if (fromIndex < 0 || fromIndex >= rows.value.length || toIndex < 0 || toIndex >= rows.value.length || fromIndex === toIndex) return false;
|
|
619
|
+
const [movedRow] = rows.value.splice(fromIndex, 1);
|
|
620
|
+
rows.value.splice(toIndex, 0, movedRow);
|
|
621
|
+
const newModifications = {};
|
|
622
|
+
const newExpandStates = {};
|
|
623
|
+
for (const [key, value] of Object.entries(rowModifications.value)) {
|
|
624
|
+
const idx = parseInt(key);
|
|
625
|
+
let newIdx = idx;
|
|
626
|
+
if (idx === fromIndex) newIdx = toIndex;
|
|
627
|
+
else if (fromIndex < toIndex) {
|
|
628
|
+
if (idx > fromIndex && idx <= toIndex) newIdx = idx - 1;
|
|
629
|
+
} else if (idx >= toIndex && idx < fromIndex) newIdx = idx + 1;
|
|
630
|
+
newModifications[newIdx] = value;
|
|
631
|
+
}
|
|
632
|
+
for (const [key, value] of Object.entries(rowExpandStates.value)) {
|
|
633
|
+
const idx = parseInt(key);
|
|
634
|
+
let newIdx = idx;
|
|
635
|
+
if (idx === fromIndex) newIdx = toIndex;
|
|
636
|
+
else if (fromIndex < toIndex) {
|
|
637
|
+
if (idx > fromIndex && idx <= toIndex) newIdx = idx - 1;
|
|
638
|
+
} else if (idx >= toIndex && idx < fromIndex) newIdx = idx + 1;
|
|
639
|
+
newExpandStates[newIdx] = value;
|
|
640
|
+
}
|
|
641
|
+
rowModifications.value = newModifications;
|
|
642
|
+
rowExpandStates.value = newExpandStates;
|
|
643
|
+
return true;
|
|
644
|
+
};
|
|
645
|
+
return {
|
|
646
|
+
columns,
|
|
647
|
+
config,
|
|
648
|
+
connectionHandles,
|
|
649
|
+
connectionPaths,
|
|
650
|
+
display,
|
|
651
|
+
filterState,
|
|
652
|
+
ganttBars,
|
|
653
|
+
modal,
|
|
654
|
+
rows,
|
|
655
|
+
sortState,
|
|
656
|
+
table,
|
|
657
|
+
updates,
|
|
658
|
+
filteredRows,
|
|
659
|
+
hasPinnedColumns,
|
|
660
|
+
isGanttView,
|
|
661
|
+
isTreeView,
|
|
662
|
+
isDependencyGraphEnabled,
|
|
663
|
+
numberedRowWidth,
|
|
664
|
+
zeroColumn,
|
|
665
|
+
linkResolver,
|
|
666
|
+
addRow,
|
|
667
|
+
clearFilter,
|
|
668
|
+
closeModal,
|
|
669
|
+
createConnection,
|
|
670
|
+
deleteConnection,
|
|
671
|
+
deleteRow,
|
|
672
|
+
duplicateRow,
|
|
673
|
+
getCellData,
|
|
674
|
+
getCellDisplayValue,
|
|
675
|
+
getConnectionsForBar,
|
|
676
|
+
getFormattedValue,
|
|
677
|
+
getHandlesForBar,
|
|
678
|
+
getHeaderCellStyle,
|
|
679
|
+
getRowExpandSymbol,
|
|
680
|
+
insertRowAbove,
|
|
681
|
+
insertRowBelow,
|
|
682
|
+
isRowGantt,
|
|
683
|
+
isRowVisible,
|
|
684
|
+
moveRow,
|
|
685
|
+
registerConnectionHandle,
|
|
686
|
+
registerGanttBar,
|
|
687
|
+
resizeColumn,
|
|
688
|
+
setCellData,
|
|
689
|
+
setCellText,
|
|
690
|
+
setFilter,
|
|
691
|
+
sortByColumn,
|
|
692
|
+
toggleRowExpand,
|
|
693
|
+
unregisterConnectionHandle,
|
|
694
|
+
unregisterGanttBar,
|
|
695
|
+
updateGanttBar,
|
|
696
|
+
updateRows
|
|
697
|
+
};
|
|
698
|
+
})();
|
|
699
|
+
};
|
|
700
|
+
//#endregion
|
|
701
|
+
//#region src/components/ACell.vue?vue&type=script&setup=true&lang.ts
|
|
702
|
+
var _hoisted_1$10 = [
|
|
703
|
+
"data-colindex",
|
|
704
|
+
"data-rowindex",
|
|
705
|
+
"data-editable",
|
|
706
|
+
"contenteditable",
|
|
707
|
+
"tabindex"
|
|
708
|
+
];
|
|
709
|
+
var _hoisted_2$9 = ["innerHTML"];
|
|
710
|
+
var _hoisted_3$7 = { key: 4 };
|
|
711
|
+
//#endregion
|
|
712
|
+
//#region src/components/ACell.vue
|
|
713
|
+
var ACell_default = /* @__PURE__ */ defineComponent({
|
|
714
|
+
__name: "ACell",
|
|
715
|
+
props: {
|
|
716
|
+
colIndex: {},
|
|
717
|
+
rowIndex: {},
|
|
718
|
+
store: {},
|
|
719
|
+
addNavigation: {
|
|
720
|
+
type: [Boolean, Object],
|
|
721
|
+
default: true
|
|
722
|
+
},
|
|
723
|
+
tabIndex: { default: 0 },
|
|
724
|
+
pinned: {
|
|
725
|
+
type: Boolean,
|
|
726
|
+
default: false
|
|
727
|
+
},
|
|
728
|
+
debounce: { default: 300 }
|
|
729
|
+
},
|
|
730
|
+
setup(__props, { expose: __expose }) {
|
|
731
|
+
const cellRef = useTemplateRef("cell");
|
|
732
|
+
const originalData = __props.store.getCellData(__props.colIndex, __props.rowIndex);
|
|
733
|
+
const currentData = ref("");
|
|
734
|
+
const cellModified = ref(false);
|
|
735
|
+
const column = __props.store.columns[__props.colIndex];
|
|
736
|
+
const row = __props.store.rows[__props.rowIndex];
|
|
737
|
+
const textAlign = column.align || "center";
|
|
738
|
+
const cellWidth = column.width || "40ch";
|
|
739
|
+
const displayValue = computed(() => __props.store.getCellDisplayValue(__props.colIndex, __props.rowIndex));
|
|
740
|
+
const resolvedText = ref(null);
|
|
741
|
+
onMounted(() => {
|
|
742
|
+
if (!column.linkDoctype) return;
|
|
743
|
+
const raw = __props.store.getCellData(__props.colIndex, __props.rowIndex);
|
|
744
|
+
if (raw !== null && raw !== void 0 && typeof raw === "object") {
|
|
745
|
+
const obj = raw;
|
|
746
|
+
const display = obj.displayText ?? obj.id;
|
|
747
|
+
if (typeof display === "string" || typeof display === "number") resolvedText.value = String(display);
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
const resolver = __props.store.linkResolver;
|
|
751
|
+
if (!resolver || typeof raw !== "string" || raw === "") return;
|
|
752
|
+
resolver(column.linkDoctype, raw).then((text) => {
|
|
753
|
+
if (text != null) resolvedText.value = text;
|
|
754
|
+
return text;
|
|
755
|
+
});
|
|
756
|
+
});
|
|
757
|
+
const renderedValue = computed(() => resolvedText.value ?? displayValue.value);
|
|
758
|
+
const badgeFromFormat = computed(() => {
|
|
759
|
+
if (column.cellComponent) return void 0;
|
|
760
|
+
const value = renderedValue.value;
|
|
761
|
+
return isBadgeDescriptor(value) ? value : void 0;
|
|
762
|
+
});
|
|
763
|
+
const badgeFromOptions = computed(() => {
|
|
764
|
+
if (column.cellComponent || badgeFromFormat.value) return void 0;
|
|
765
|
+
if (!hasBadgeOptions(column.options)) return void 0;
|
|
766
|
+
return {
|
|
767
|
+
value: __props.store.getCellData(__props.colIndex, __props.rowIndex),
|
|
768
|
+
options: column.options,
|
|
769
|
+
presentation: "cell-fill"
|
|
770
|
+
};
|
|
771
|
+
});
|
|
772
|
+
const usesBadgeDisplay = computed(() => !!column.cellComponent || badgeFromFormat.value !== void 0 || hasBadgeOptions(column.options));
|
|
773
|
+
const isContentEditable = computed(() => column.edit && !usesBadgeDisplay.value);
|
|
774
|
+
const cellComponentBindings = computed(() => {
|
|
775
|
+
const props = { ...column.cellComponentProps };
|
|
776
|
+
if (column.cellComponent !== "ABadge") return {
|
|
777
|
+
...props,
|
|
778
|
+
value: renderedValue.value
|
|
779
|
+
};
|
|
780
|
+
if (isBadgeDescriptor(renderedValue.value)) return {
|
|
781
|
+
presentation: "cell-fill",
|
|
782
|
+
...props,
|
|
783
|
+
...renderedValue.value
|
|
784
|
+
};
|
|
785
|
+
return {
|
|
786
|
+
presentation: "cell-fill",
|
|
787
|
+
options: column.options,
|
|
788
|
+
...props,
|
|
789
|
+
value: __props.store.getCellData(__props.colIndex, __props.rowIndex)
|
|
790
|
+
};
|
|
791
|
+
});
|
|
792
|
+
const isHtmlValue = computed(() => {
|
|
793
|
+
return typeof renderedValue.value === "string" ? isHtmlString(renderedValue.value) : false;
|
|
794
|
+
});
|
|
795
|
+
const cellStyle = computed(() => {
|
|
796
|
+
return {
|
|
797
|
+
textAlign,
|
|
798
|
+
width: cellWidth,
|
|
799
|
+
fontWeight: !cellModified.value ? "inherit" : "bold",
|
|
800
|
+
paddingLeft: getIndent(__props.colIndex, __props.store.display[__props.rowIndex]?.indent)
|
|
801
|
+
};
|
|
802
|
+
});
|
|
803
|
+
const cellClasses = computed(() => {
|
|
804
|
+
return {
|
|
805
|
+
"sticky-column": __props.pinned,
|
|
806
|
+
"cell-modified": cellModified.value,
|
|
807
|
+
"atable-cell--badge-fill": usesBadgeDisplay.value
|
|
808
|
+
};
|
|
809
|
+
});
|
|
810
|
+
const onCellClick = () => {
|
|
811
|
+
selectAllText();
|
|
812
|
+
showModal();
|
|
813
|
+
};
|
|
814
|
+
const showModal = () => {
|
|
815
|
+
const { left, bottom, width, height } = useElementBounding(cellRef);
|
|
816
|
+
if (column.mask) {}
|
|
817
|
+
if (column.modalComponent) __props.store.$patch((state) => {
|
|
818
|
+
state.modal.visible = true;
|
|
819
|
+
state.modal.colIndex = __props.colIndex;
|
|
820
|
+
state.modal.rowIndex = __props.rowIndex;
|
|
821
|
+
state.modal.left = left.value;
|
|
822
|
+
state.modal.bottom = bottom.value;
|
|
823
|
+
state.modal.width = width.value;
|
|
824
|
+
state.modal.height = height.value;
|
|
825
|
+
state.modal.cell = cellRef.value;
|
|
826
|
+
if (typeof column.modalComponent === "function") state.modal.component = column.modalComponent({
|
|
827
|
+
table: __props.store.table,
|
|
828
|
+
row,
|
|
829
|
+
column
|
|
830
|
+
});
|
|
831
|
+
else state.modal.component = column.modalComponent;
|
|
832
|
+
state.modal.componentProps = column.modalComponentExtraProps;
|
|
833
|
+
});
|
|
834
|
+
};
|
|
835
|
+
if (__props.addNavigation) {
|
|
836
|
+
let handlers = {
|
|
837
|
+
...defaultKeypressHandlers,
|
|
838
|
+
"keydown.f2": showModal,
|
|
839
|
+
"keydown.alt.up": showModal,
|
|
840
|
+
"keydown.alt.down": showModal,
|
|
841
|
+
"keydown.alt.left": showModal,
|
|
842
|
+
"keydown.alt.right": showModal
|
|
843
|
+
};
|
|
844
|
+
if (typeof __props.addNavigation === "object") handlers = {
|
|
845
|
+
...handlers,
|
|
846
|
+
...__props.addNavigation
|
|
847
|
+
};
|
|
848
|
+
useKeyboardNav([{
|
|
849
|
+
selectors: cellRef,
|
|
850
|
+
handlers
|
|
851
|
+
}]);
|
|
852
|
+
}
|
|
853
|
+
const selectAllText = () => {
|
|
854
|
+
if (cellRef.value && column.edit) {
|
|
855
|
+
const selection = window.getSelection();
|
|
856
|
+
if (selection) try {
|
|
857
|
+
const range = document.createRange();
|
|
858
|
+
if (range.selectNodeContents) {
|
|
859
|
+
range.selectNodeContents(cellRef.value);
|
|
860
|
+
selection.removeAllRanges();
|
|
861
|
+
selection.addRange(range);
|
|
862
|
+
}
|
|
863
|
+
} catch {}
|
|
864
|
+
}
|
|
865
|
+
};
|
|
866
|
+
const onFocus = () => {
|
|
867
|
+
if (cellRef.value) {
|
|
868
|
+
currentData.value = cellRef.value.textContent;
|
|
869
|
+
selectAllText();
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
const saveCursorPosition = () => {
|
|
873
|
+
try {
|
|
874
|
+
const selection = window.getSelection();
|
|
875
|
+
if (selection && selection.rangeCount > 0 && cellRef.value) {
|
|
876
|
+
const range = selection.getRangeAt(0);
|
|
877
|
+
const preCaretRange = range.cloneRange();
|
|
878
|
+
if (preCaretRange.selectNodeContents && preCaretRange.setEnd) {
|
|
879
|
+
preCaretRange.selectNodeContents(cellRef.value);
|
|
880
|
+
preCaretRange.setEnd(range.endContainer, range.endOffset);
|
|
881
|
+
return preCaretRange.toString().length;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
} catch {}
|
|
885
|
+
return 0;
|
|
886
|
+
};
|
|
887
|
+
const restoreCursorPosition = (position) => {
|
|
888
|
+
if (!cellRef.value) return;
|
|
889
|
+
try {
|
|
890
|
+
const selection = window.getSelection();
|
|
891
|
+
if (!selection) return;
|
|
892
|
+
let charIndex = 0;
|
|
893
|
+
const walker = document.createTreeWalker ? document.createTreeWalker(cellRef.value, NodeFilter.SHOW_TEXT, null) : null;
|
|
894
|
+
if (!walker) return;
|
|
895
|
+
let node;
|
|
896
|
+
let range = null;
|
|
897
|
+
while (node = walker.nextNode()) {
|
|
898
|
+
const textNode = node;
|
|
899
|
+
const nextCharIndex = charIndex + textNode.textContent.length;
|
|
900
|
+
if (position <= nextCharIndex) {
|
|
901
|
+
range = document.createRange();
|
|
902
|
+
if (range.setStart && range.setEnd) {
|
|
903
|
+
range.setStart(textNode, position - charIndex);
|
|
904
|
+
range.setEnd(textNode, position - charIndex);
|
|
905
|
+
break;
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
charIndex = nextCharIndex;
|
|
909
|
+
}
|
|
910
|
+
if (range && selection.removeAllRanges && selection.addRange) {
|
|
911
|
+
selection.removeAllRanges();
|
|
912
|
+
selection.addRange(range);
|
|
913
|
+
}
|
|
914
|
+
} catch {}
|
|
915
|
+
};
|
|
916
|
+
const updateCellData = (payload) => {
|
|
917
|
+
if (!column.edit) return;
|
|
918
|
+
const target = payload.target;
|
|
919
|
+
if (target.textContent === currentData.value) return;
|
|
920
|
+
const cursorPosition = saveCursorPosition();
|
|
921
|
+
currentData.value = target.textContent;
|
|
922
|
+
if (column.format) {
|
|
923
|
+
cellModified.value = target.textContent !== __props.store.getFormattedValue(__props.colIndex, __props.rowIndex, originalData);
|
|
924
|
+
__props.store.setCellText(__props.colIndex, __props.rowIndex, target.textContent);
|
|
925
|
+
} else {
|
|
926
|
+
cellModified.value = target.textContent !== originalData;
|
|
927
|
+
__props.store.setCellData(__props.colIndex, __props.rowIndex, target.textContent);
|
|
928
|
+
}
|
|
929
|
+
nextTick().then(() => {
|
|
930
|
+
return restoreCursorPosition(cursorPosition);
|
|
931
|
+
});
|
|
932
|
+
};
|
|
933
|
+
const debouncedUpdateCellData = useDebounceFn(updateCellData, __props.debounce);
|
|
934
|
+
__expose({ currentData });
|
|
935
|
+
return (_ctx, _cache) => {
|
|
936
|
+
return openBlock(), createElementBlock("td", {
|
|
937
|
+
ref: "cell",
|
|
938
|
+
"data-colindex": __props.colIndex,
|
|
939
|
+
"data-rowindex": __props.rowIndex,
|
|
940
|
+
"data-editable": unref(column).edit,
|
|
941
|
+
contenteditable: isContentEditable.value,
|
|
942
|
+
tabindex: __props.tabIndex,
|
|
943
|
+
spellcheck: false,
|
|
944
|
+
style: normalizeStyle(cellStyle.value),
|
|
945
|
+
class: normalizeClass(["atable-cell", cellClasses.value]),
|
|
946
|
+
onFocus,
|
|
947
|
+
onPaste: updateCellData,
|
|
948
|
+
onInput: _cache[0] || (_cache[0] = (...args) => unref(debouncedUpdateCellData) && unref(debouncedUpdateCellData)(...args)),
|
|
949
|
+
onClick: onCellClick
|
|
950
|
+
}, [unref(column).cellComponent ? (openBlock(), createBlock(resolveDynamicComponent(unref(column).cellComponent), normalizeProps(mergeProps({ key: 0 }, cellComponentBindings.value)), null, 16)) : badgeFromFormat.value ? (openBlock(), createBlock(resolveDynamicComponent("ABadge"), mergeProps({ key: 1 }, badgeFromFormat.value, { presentation: "cell-fill" }), null, 16)) : badgeFromOptions.value ? (openBlock(), createBlock(resolveDynamicComponent("ABadge"), normalizeProps(mergeProps({ key: 2 }, badgeFromOptions.value)), null, 16)) : isHtmlValue.value ? (openBlock(), createElementBlock("span", {
|
|
951
|
+
key: 3,
|
|
952
|
+
innerHTML: renderedValue.value
|
|
953
|
+
}, null, 8, _hoisted_2$9)) : (openBlock(), createElementBlock("span", _hoisted_3$7, toDisplayString(renderedValue.value), 1))], 46, _hoisted_1$10);
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
});
|
|
957
|
+
//#endregion
|
|
958
|
+
//#region src/components/AGanttCell.vue?vue&type=script&setup=true&lang.ts
|
|
959
|
+
var _hoisted_1$9 = ["colspan"];
|
|
960
|
+
var _hoisted_2$8 = {
|
|
961
|
+
ref: "container",
|
|
962
|
+
class: "gantt-container"
|
|
963
|
+
};
|
|
964
|
+
var _hoisted_3$6 = ["data-rowindex", "data-colindex"];
|
|
965
|
+
var _hoisted_4$5 = {
|
|
966
|
+
key: 2,
|
|
967
|
+
class: "gantt-label"
|
|
968
|
+
};
|
|
969
|
+
var _hoisted_5$3 = [
|
|
970
|
+
"x1",
|
|
971
|
+
"y1",
|
|
972
|
+
"x2",
|
|
973
|
+
"y2"
|
|
974
|
+
];
|
|
975
|
+
var AGanttCell_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
976
|
+
__name: "AGanttCell",
|
|
977
|
+
props: {
|
|
978
|
+
store: {},
|
|
979
|
+
columnsCount: {},
|
|
980
|
+
rowIndex: {},
|
|
981
|
+
colIndex: {},
|
|
982
|
+
start: { default: 0 },
|
|
983
|
+
end: { default: 0 },
|
|
984
|
+
colspan: { default: 1 },
|
|
985
|
+
label: { default: "" },
|
|
986
|
+
color: { default: "#cccccc" }
|
|
987
|
+
},
|
|
988
|
+
emits: ["connection:create"],
|
|
989
|
+
setup(__props, { expose: __expose, emit: __emit }) {
|
|
990
|
+
useCssVars((_ctx) => ({
|
|
991
|
+
"v564d6da1": barColor.value,
|
|
992
|
+
"v4f540c19": _ctx.colspan
|
|
993
|
+
}));
|
|
994
|
+
const emit = __emit;
|
|
995
|
+
const barColor = ref(__props.color.length >= 6 ? __props.color : "#cccccc");
|
|
996
|
+
const barId = `gantt-bar-row-${__props.rowIndex}-col-${__props.colIndex}`;
|
|
997
|
+
const containerRef = useTemplateRef("container");
|
|
998
|
+
const barRef = useTemplateRef("bar");
|
|
999
|
+
const leftResizeHandleRef = useTemplateRef("leftResizeHandle");
|
|
1000
|
+
const rightResizeHandleRef = useTemplateRef("rightResizeHandle");
|
|
1001
|
+
const leftConnectionHandleRef = useTemplateRef("leftConnectionHandle");
|
|
1002
|
+
const rightConnectionHandleRef = useTemplateRef("rightConnectionHandle");
|
|
1003
|
+
const { width: totalBarWidth } = useElementBounding(containerRef);
|
|
1004
|
+
const { left: barLeft, right: barRight } = useElementBounding(barRef);
|
|
1005
|
+
const currentStart = ref(__props.start);
|
|
1006
|
+
const currentEnd = ref(__props.end || currentStart.value + __props.colspan);
|
|
1007
|
+
const isLeftConnectionVisible = ref(false);
|
|
1008
|
+
const isRightConnectionVisible = ref(false);
|
|
1009
|
+
const isLeftConnectionDragging = ref(false);
|
|
1010
|
+
const isRightConnectionDragging = ref(false);
|
|
1011
|
+
const showDragPreview = ref(false);
|
|
1012
|
+
const dragPreview = ref({
|
|
1013
|
+
startX: 0,
|
|
1014
|
+
startY: 0,
|
|
1015
|
+
endX: 0,
|
|
1016
|
+
endY: 0
|
|
1017
|
+
});
|
|
1018
|
+
const isAnyDragging = computed(() => isBarDragging.value || isLeftResizing.value || isRightResizing.value);
|
|
1019
|
+
const pixelsPerColumn = computed(() => __props.colspan > 0 ? totalBarWidth.value / __props.colspan : 0);
|
|
1020
|
+
const barStyle = computed(() => {
|
|
1021
|
+
const startPercent = currentStart.value / __props.colspan * 100;
|
|
1022
|
+
const endPercent = currentEnd.value / __props.colspan * 100;
|
|
1023
|
+
return {
|
|
1024
|
+
left: `${startPercent}%`,
|
|
1025
|
+
width: `${endPercent - startPercent}%`,
|
|
1026
|
+
backgroundColor: barColor.value
|
|
1027
|
+
};
|
|
1028
|
+
});
|
|
1029
|
+
const connectionDragStyle = computed(() => ({
|
|
1030
|
+
position: "fixed",
|
|
1031
|
+
top: 0,
|
|
1032
|
+
left: 0,
|
|
1033
|
+
width: "100vw",
|
|
1034
|
+
height: "100vh",
|
|
1035
|
+
pointerEvents: "none",
|
|
1036
|
+
zIndex: 1e3
|
|
1037
|
+
}));
|
|
1038
|
+
const dragStartData = ref({
|
|
1039
|
+
startX: 0,
|
|
1040
|
+
startPos: 0
|
|
1041
|
+
});
|
|
1042
|
+
const { isDragging: isLeftResizing } = useDraggable(leftResizeHandleRef, {
|
|
1043
|
+
axis: "x",
|
|
1044
|
+
onStart: () => setupDragStart(barLeft.value, currentStart.value),
|
|
1045
|
+
onMove: ({ x }) => handleLeftResize(x),
|
|
1046
|
+
onEnd: ({ x }) => finishLeftResize(x)
|
|
1047
|
+
});
|
|
1048
|
+
const { isDragging: isRightResizing } = useDraggable(rightResizeHandleRef, {
|
|
1049
|
+
axis: "x",
|
|
1050
|
+
onStart: () => setupDragStart(barRight.value, currentEnd.value),
|
|
1051
|
+
onMove: ({ x }) => handleRightResize(x),
|
|
1052
|
+
onEnd: ({ x }) => finishRightResize(x)
|
|
1053
|
+
});
|
|
1054
|
+
const { isDragging: isBarDragging } = useDraggable(barRef, {
|
|
1055
|
+
exact: true,
|
|
1056
|
+
axis: "x",
|
|
1057
|
+
onStart: () => setupDragStart(barLeft.value, currentStart.value),
|
|
1058
|
+
onMove: ({ x }) => handleBarMove(x),
|
|
1059
|
+
onEnd: ({ x }) => finishBarMove(x)
|
|
1060
|
+
});
|
|
1061
|
+
onMounted(() => {
|
|
1062
|
+
registerGanttComponents();
|
|
1063
|
+
});
|
|
1064
|
+
onUnmounted(() => {
|
|
1065
|
+
unregisterGanttComponents();
|
|
1066
|
+
});
|
|
1067
|
+
function setupDragStart(startX, startPos) {
|
|
1068
|
+
if (barRef.value) barRef.value.style.transition = "none";
|
|
1069
|
+
dragStartData.value = {
|
|
1070
|
+
startX,
|
|
1071
|
+
startPos
|
|
1072
|
+
};
|
|
1073
|
+
}
|
|
1074
|
+
function handleLeftResize(x) {
|
|
1075
|
+
if (!isLeftResizing.value || !barRef.value) return;
|
|
1076
|
+
const deltaColumns = (x - dragStartData.value.startX) / pixelsPerColumn.value;
|
|
1077
|
+
const newStart = Math.max(0, Math.min(currentEnd.value - 1, dragStartData.value.startPos + deltaColumns));
|
|
1078
|
+
barRef.value.style.left = `${newStart / __props.colspan * 100}%`;
|
|
1079
|
+
barRef.value.style.width = `${(currentEnd.value - newStart) / __props.colspan * 100}%`;
|
|
1080
|
+
}
|
|
1081
|
+
function finishLeftResize(x) {
|
|
1082
|
+
if (!barRef.value) return;
|
|
1083
|
+
const deltaX = x - dragStartData.value.startX;
|
|
1084
|
+
const deltaColumns = Math.round(deltaX / pixelsPerColumn.value);
|
|
1085
|
+
const oldStart = currentStart.value;
|
|
1086
|
+
const newStart = Math.max(0, Math.min(currentEnd.value - 1, dragStartData.value.startPos + deltaColumns));
|
|
1087
|
+
currentStart.value = newStart;
|
|
1088
|
+
__props.store.updateGanttBar({
|
|
1089
|
+
rowIndex: __props.rowIndex,
|
|
1090
|
+
colIndex: __props.colIndex,
|
|
1091
|
+
type: "resize",
|
|
1092
|
+
edge: "start",
|
|
1093
|
+
oldStart,
|
|
1094
|
+
newStart,
|
|
1095
|
+
end: currentEnd.value,
|
|
1096
|
+
delta: deltaColumns,
|
|
1097
|
+
oldColspan: currentEnd.value - oldStart,
|
|
1098
|
+
newColspan: currentEnd.value - newStart
|
|
1099
|
+
});
|
|
1100
|
+
}
|
|
1101
|
+
function handleRightResize(x) {
|
|
1102
|
+
if (!isRightResizing.value || !barRef.value) return;
|
|
1103
|
+
const deltaColumns = (x - dragStartData.value.startX) / pixelsPerColumn.value;
|
|
1104
|
+
const newEnd = Math.max(currentStart.value + 1, Math.min(__props.columnsCount, dragStartData.value.startPos + deltaColumns));
|
|
1105
|
+
barRef.value.style.width = `${(newEnd - currentStart.value) / __props.colspan * 100}%`;
|
|
1106
|
+
}
|
|
1107
|
+
function finishRightResize(x) {
|
|
1108
|
+
if (!barRef.value) return;
|
|
1109
|
+
const deltaX = x - dragStartData.value.startX;
|
|
1110
|
+
const deltaColumns = Math.round(deltaX / pixelsPerColumn.value);
|
|
1111
|
+
const oldEnd = currentEnd.value;
|
|
1112
|
+
const newEnd = Math.max(currentStart.value + 1, Math.min(__props.columnsCount, dragStartData.value.startPos + deltaColumns));
|
|
1113
|
+
currentEnd.value = newEnd;
|
|
1114
|
+
__props.store.updateGanttBar({
|
|
1115
|
+
rowIndex: __props.rowIndex,
|
|
1116
|
+
colIndex: __props.colIndex,
|
|
1117
|
+
type: "resize",
|
|
1118
|
+
edge: "end",
|
|
1119
|
+
oldEnd,
|
|
1120
|
+
newEnd,
|
|
1121
|
+
start: currentStart.value,
|
|
1122
|
+
delta: deltaColumns,
|
|
1123
|
+
oldColspan: oldEnd - currentStart.value,
|
|
1124
|
+
newColspan: newEnd - currentStart.value
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
1127
|
+
function handleBarMove(x) {
|
|
1128
|
+
if (!isBarDragging.value || !barRef.value) return;
|
|
1129
|
+
const deltaColumns = (x - dragStartData.value.startX) / pixelsPerColumn.value;
|
|
1130
|
+
const barWidth = currentEnd.value - currentStart.value;
|
|
1131
|
+
const newStart = Math.max(0, Math.min(dragStartData.value.startPos + deltaColumns, __props.columnsCount - barWidth));
|
|
1132
|
+
barRef.value.style.left = `${newStart / __props.colspan * 100}%`;
|
|
1133
|
+
}
|
|
1134
|
+
function finishBarMove(x) {
|
|
1135
|
+
if (!barRef.value) return;
|
|
1136
|
+
const deltaX = x - dragStartData.value.startX;
|
|
1137
|
+
const deltaColumns = Math.round(deltaX / pixelsPerColumn.value);
|
|
1138
|
+
const barWidth = currentEnd.value - currentStart.value;
|
|
1139
|
+
const oldStart = currentStart.value;
|
|
1140
|
+
const oldEnd = currentEnd.value;
|
|
1141
|
+
let newStart = dragStartData.value.startPos + deltaColumns;
|
|
1142
|
+
let newEnd = newStart + barWidth;
|
|
1143
|
+
if (newStart < 0) {
|
|
1144
|
+
newStart = 0;
|
|
1145
|
+
newEnd = barWidth;
|
|
1146
|
+
} else if (newEnd > __props.columnsCount) {
|
|
1147
|
+
newEnd = __props.columnsCount;
|
|
1148
|
+
newStart = newEnd - barWidth;
|
|
1149
|
+
}
|
|
1150
|
+
currentStart.value = newStart;
|
|
1151
|
+
currentEnd.value = newEnd;
|
|
1152
|
+
__props.store.updateGanttBar({
|
|
1153
|
+
rowIndex: __props.rowIndex,
|
|
1154
|
+
colIndex: __props.colIndex,
|
|
1155
|
+
type: "bar",
|
|
1156
|
+
oldStart,
|
|
1157
|
+
oldEnd,
|
|
1158
|
+
newStart,
|
|
1159
|
+
newEnd,
|
|
1160
|
+
delta: deltaColumns,
|
|
1161
|
+
colspan: newEnd - newStart
|
|
1162
|
+
});
|
|
1163
|
+
}
|
|
1164
|
+
function registerGanttComponents() {
|
|
1165
|
+
const { x: barX, y: barY } = useElementBounding(barRef);
|
|
1166
|
+
const { x: leftX, y: leftY } = useElementBounding(leftConnectionHandleRef);
|
|
1167
|
+
const { x: rightX, y: rightY } = useElementBounding(rightConnectionHandleRef);
|
|
1168
|
+
__props.store.registerGanttBar({
|
|
1169
|
+
id: barId,
|
|
1170
|
+
rowIndex: __props.rowIndex,
|
|
1171
|
+
colIndex: __props.colIndex,
|
|
1172
|
+
startIndex: currentStart,
|
|
1173
|
+
endIndex: currentEnd,
|
|
1174
|
+
color: barColor,
|
|
1175
|
+
label: __props.label,
|
|
1176
|
+
position: {
|
|
1177
|
+
x: barX,
|
|
1178
|
+
y: barY
|
|
1179
|
+
}
|
|
1180
|
+
});
|
|
1181
|
+
if (__props.store.isDependencyGraphEnabled) {
|
|
1182
|
+
__props.store.registerConnectionHandle({
|
|
1183
|
+
id: `${barId}-connection-left`,
|
|
1184
|
+
rowIndex: __props.rowIndex,
|
|
1185
|
+
colIndex: __props.colIndex,
|
|
1186
|
+
side: "left",
|
|
1187
|
+
position: {
|
|
1188
|
+
x: leftX,
|
|
1189
|
+
y: leftY
|
|
1190
|
+
},
|
|
1191
|
+
visible: isLeftConnectionVisible,
|
|
1192
|
+
barId
|
|
1193
|
+
});
|
|
1194
|
+
__props.store.registerConnectionHandle({
|
|
1195
|
+
id: `${barId}-connection-right`,
|
|
1196
|
+
rowIndex: __props.rowIndex,
|
|
1197
|
+
colIndex: __props.colIndex,
|
|
1198
|
+
side: "right",
|
|
1199
|
+
position: {
|
|
1200
|
+
x: rightX,
|
|
1201
|
+
y: rightY
|
|
1202
|
+
},
|
|
1203
|
+
visible: isRightConnectionVisible,
|
|
1204
|
+
barId
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
function unregisterGanttComponents() {
|
|
1209
|
+
__props.store.unregisterGanttBar(barId);
|
|
1210
|
+
if (__props.store.isDependencyGraphEnabled) {
|
|
1211
|
+
__props.store.unregisterConnectionHandle(`${barId}-connection-left`);
|
|
1212
|
+
__props.store.unregisterConnectionHandle(`${barId}-connection-right`);
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
function showConnectionHandles() {
|
|
1216
|
+
if (__props.store.isDependencyGraphEnabled) {
|
|
1217
|
+
isLeftConnectionVisible.value = true;
|
|
1218
|
+
isRightConnectionVisible.value = true;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
function hideConnectionHandles() {
|
|
1222
|
+
if (!isLeftConnectionDragging.value && !isRightConnectionDragging.value) {
|
|
1223
|
+
isLeftConnectionVisible.value = false;
|
|
1224
|
+
isRightConnectionVisible.value = false;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
function startConnectionDrag(side, event) {
|
|
1228
|
+
event.preventDefault();
|
|
1229
|
+
event.stopPropagation();
|
|
1230
|
+
showDragPreview.value = true;
|
|
1231
|
+
if (side === "left") isLeftConnectionDragging.value = true;
|
|
1232
|
+
else isRightConnectionDragging.value = true;
|
|
1233
|
+
const handle = side === "left" ? leftConnectionHandleRef.value : rightConnectionHandleRef.value;
|
|
1234
|
+
if (handle) {
|
|
1235
|
+
const handleRect = handle.getBoundingClientRect();
|
|
1236
|
+
const centerX = handleRect.left + handleRect.width / 2;
|
|
1237
|
+
const centerY = handleRect.top + handleRect.height / 2;
|
|
1238
|
+
dragPreview.value = {
|
|
1239
|
+
startX: centerX,
|
|
1240
|
+
startY: centerY,
|
|
1241
|
+
endX: centerX,
|
|
1242
|
+
endY: centerY
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
const handleMouseMove = (moveEvent) => {
|
|
1246
|
+
dragPreview.value.endX = moveEvent.clientX;
|
|
1247
|
+
dragPreview.value.endY = moveEvent.clientY;
|
|
1248
|
+
};
|
|
1249
|
+
const handleMouseUp = (upEvent) => {
|
|
1250
|
+
handleConnectionDrop(upEvent, side);
|
|
1251
|
+
cleanupConnectionDrag(handleMouseMove, handleMouseUp);
|
|
1252
|
+
};
|
|
1253
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
1254
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
1255
|
+
}
|
|
1256
|
+
function handleConnectionDrop(upEvent, sourceSide) {
|
|
1257
|
+
const targetHandle = document.elementFromPoint(upEvent.clientX, upEvent.clientY)?.closest(".connection-handle");
|
|
1258
|
+
if (targetHandle && targetHandle !== (sourceSide === "left" ? leftConnectionHandleRef.value : rightConnectionHandleRef.value)) {
|
|
1259
|
+
const targetBar = targetHandle.closest(".gantt-bar");
|
|
1260
|
+
if (targetBar) {
|
|
1261
|
+
const targetRowIndex = parseInt(targetBar.getAttribute("data-rowindex") || "0");
|
|
1262
|
+
const targetColIndex = parseInt(targetBar.getAttribute("data-colindex") || "0");
|
|
1263
|
+
const targetSide = targetHandle.classList.contains("left-connection-handle") ? "left" : "right";
|
|
1264
|
+
const targetBarId = `gantt-bar-row-${targetRowIndex}-col-${targetColIndex}`;
|
|
1265
|
+
const connection = __props.store.createConnection(`${barId}-connection-${sourceSide}`, `${targetBarId}-connection-${targetSide}`);
|
|
1266
|
+
if (connection) emit("connection:create", connection);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
function cleanupConnectionDrag(handleMouseMove, handleMouseUp) {
|
|
1271
|
+
showDragPreview.value = false;
|
|
1272
|
+
isLeftConnectionDragging.value = false;
|
|
1273
|
+
isRightConnectionDragging.value = false;
|
|
1274
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
1275
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
1276
|
+
if (!barRef.value?.matches(":hover")) hideConnectionHandles();
|
|
1277
|
+
}
|
|
1278
|
+
__expose({
|
|
1279
|
+
barStyle,
|
|
1280
|
+
cleanupConnectionDrag,
|
|
1281
|
+
currentEnd,
|
|
1282
|
+
handleConnectionDrop,
|
|
1283
|
+
isLeftConnectionDragging,
|
|
1284
|
+
isLeftConnectionVisible,
|
|
1285
|
+
isRightConnectionDragging,
|
|
1286
|
+
isRightConnectionVisible,
|
|
1287
|
+
showDragPreview
|
|
1288
|
+
});
|
|
1289
|
+
return (_ctx, _cache) => {
|
|
1290
|
+
return openBlock(), createElementBlock("td", {
|
|
1291
|
+
class: "aganttcell",
|
|
1292
|
+
colspan: __props.colspan
|
|
1293
|
+
}, [createElementVNode("div", _hoisted_2$8, [createElementVNode("div", {
|
|
1294
|
+
ref: "bar",
|
|
1295
|
+
"data-rowindex": __props.rowIndex,
|
|
1296
|
+
"data-colindex": __props.colIndex,
|
|
1297
|
+
class: normalizeClass(["gantt-bar", { "is-dragging": isAnyDragging.value }]),
|
|
1298
|
+
style: normalizeStyle(barStyle.value),
|
|
1299
|
+
onMouseenter: showConnectionHandles,
|
|
1300
|
+
onMouseleave: hideConnectionHandles
|
|
1301
|
+
}, [
|
|
1302
|
+
__props.store.isDependencyGraphEnabled ? (openBlock(), createElementBlock("div", {
|
|
1303
|
+
key: 0,
|
|
1304
|
+
ref: "leftConnectionHandle",
|
|
1305
|
+
class: normalizeClass(["connection-handle left-connection-handle", {
|
|
1306
|
+
visible: isLeftConnectionVisible.value,
|
|
1307
|
+
"is-dragging": isLeftConnectionDragging.value
|
|
1308
|
+
}]),
|
|
1309
|
+
onMousedown: _cache[0] || (_cache[0] = withModifiers(($event) => startConnectionDrag("left", $event), ["stop"]))
|
|
1310
|
+
}, [..._cache[2] || (_cache[2] = [createElementVNode("div", { class: "connection-dot" }, null, -1)])], 34)) : createCommentVNode("", true),
|
|
1311
|
+
__props.store.isDependencyGraphEnabled ? (openBlock(), createElementBlock("div", {
|
|
1312
|
+
key: 1,
|
|
1313
|
+
ref: "rightConnectionHandle",
|
|
1314
|
+
class: normalizeClass(["connection-handle right-connection-handle", {
|
|
1315
|
+
visible: isRightConnectionVisible.value,
|
|
1316
|
+
"is-dragging": isRightConnectionDragging.value
|
|
1317
|
+
}]),
|
|
1318
|
+
onMousedown: _cache[1] || (_cache[1] = withModifiers(($event) => startConnectionDrag("right", $event), ["stop"]))
|
|
1319
|
+
}, [..._cache[3] || (_cache[3] = [createElementVNode("div", { class: "connection-dot" }, null, -1)])], 34)) : createCommentVNode("", true),
|
|
1320
|
+
createElementVNode("div", {
|
|
1321
|
+
ref: "leftResizeHandle",
|
|
1322
|
+
class: normalizeClass(["resize-handle left-resize-handle", { "is-dragging": unref(isLeftResizing) }])
|
|
1323
|
+
}, [..._cache[4] || (_cache[4] = [createElementVNode("div", { class: "handle-grip" }, null, -1), createElementVNode("div", { class: "vertical-indicator left-indicator" }, null, -1)])], 2),
|
|
1324
|
+
__props.label ? (openBlock(), createElementBlock("label", _hoisted_4$5, toDisplayString(__props.label), 1)) : createCommentVNode("", true),
|
|
1325
|
+
createElementVNode("div", {
|
|
1326
|
+
ref: "rightResizeHandle",
|
|
1327
|
+
class: normalizeClass(["resize-handle right-resize-handle", { "is-dragging": unref(isRightResizing) }])
|
|
1328
|
+
}, [..._cache[5] || (_cache[5] = [createElementVNode("div", { class: "handle-grip" }, null, -1), createElementVNode("div", { class: "vertical-indicator right-indicator" }, null, -1)])], 2)
|
|
1329
|
+
], 46, _hoisted_3$6)], 512), __props.store.isDependencyGraphEnabled && showDragPreview.value ? (openBlock(), createElementBlock("svg", {
|
|
1330
|
+
key: 0,
|
|
1331
|
+
style: normalizeStyle(connectionDragStyle.value)
|
|
1332
|
+
}, [createElementVNode("line", {
|
|
1333
|
+
x1: dragPreview.value.startX,
|
|
1334
|
+
y1: dragPreview.value.startY,
|
|
1335
|
+
x2: dragPreview.value.endX,
|
|
1336
|
+
y2: dragPreview.value.endY,
|
|
1337
|
+
stroke: "#2196f3",
|
|
1338
|
+
"stroke-width": "2",
|
|
1339
|
+
"stroke-dasharray": "5,5"
|
|
1340
|
+
}, null, 8, _hoisted_5$3)], 4)) : createCommentVNode("", true)], 8, _hoisted_1$9);
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
});
|
|
1344
|
+
//#endregion
|
|
1345
|
+
//#region \0plugin-vue:export-helper
|
|
1346
|
+
var _plugin_vue_export_helper_default = (sfc, props) => {
|
|
1347
|
+
const target = sfc.__vccOpts || sfc;
|
|
1348
|
+
for (const [key, val] of props) target[key] = val;
|
|
1349
|
+
return target;
|
|
1350
|
+
};
|
|
1351
|
+
//#endregion
|
|
1352
|
+
//#region src/components/AGanttCell.vue
|
|
1353
|
+
var AGanttCell_default = /*#__PURE__*/ _plugin_vue_export_helper_default(AGanttCell_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-032ef6d9"]]);
|
|
1354
|
+
//#endregion
|
|
1355
|
+
//#region src/icons/stonecrop-ui-icon-add.svg?raw
|
|
1356
|
+
var stonecrop_ui_icon_add_default = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<svg id=\"Layer_1\" data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\">\n <path d=\"M32,64C14.35,64,0,49.65,0,32S14.35,0,32,0s32,14.35,32,32-14.35,32-32,32ZM32,4c-15.44,0-28,12.56-28,28s12.56,28,28,28,28-12.56,28-28S47.44,4,32,4Z\" style=\"fill: #000; stroke-width: 0px;\"/>\n <polygon points=\"34 18 30 18 30 30 18 30 18 34 30 34 30 46 34 46 34 34 46 34 46 30 34 30 34 18\" style=\"fill: #000; stroke-width: 0px;\"/>\n</svg>\n";
|
|
1357
|
+
//#endregion
|
|
1358
|
+
//#region src/icons/stonecrop-ui-icon-delete.svg?raw
|
|
1359
|
+
var stonecrop_ui_icon_delete_default = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<svg id=\"Layer_1\" data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\">\n <path d=\"M32,64C14.35,64,0,49.65,0,32S14.35,0,32,0s32,14.35,32,32-14.35,32-32,32ZM32,4c-15.44,0-28,12.56-28,28s12.56,28,28,28,28-12.56,28-28S47.44,4,32,4Z\" style=\"fill: #000; stroke-width: 0px;\"/>\n <polygon points=\"46.84 19.99 44.01 17.16 32 29.17 19.99 17.16 17.16 19.99 29.17 32 17.16 44.01 19.99 46.84 32 34.83 44.01 46.84 46.84 44.01 34.83 32 46.84 19.99\" style=\"fill: #000; stroke-width: 0px;\"/>\n</svg>";
|
|
1360
|
+
//#endregion
|
|
1361
|
+
//#region src/icons/stonecrop-ui-icon-duplicate.svg?raw
|
|
1362
|
+
var stonecrop_ui_icon_duplicate_default = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<svg id=\"Layer_1\" data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 70.67 70.67\">\n <path d=\"M68.67,16.67h-14.67V2c0-1.1-.9-2-2-2H2C.9,0,0,.9,0,2v50c0,1.1.9,2,2,2h14.67v14.67c0,1.1.9,2,2,2h50c1.1,0,2-.9,2-2V18.67c0-1.1-.9-2-2-2ZM4,4h46v46H4V4ZM66.67,66.67H20.67v-12.67h31.33c1.1,0,2-.9,2-2v-31.33h12.67v46Z\" style=\"fill: #000; stroke-width: 0px;\"/>\n <polygon points=\"41 25 29 25 29 13 25 13 25 25 13 25 13 29 25 29 25 41 29 41 29 29 41 29 41 25\" style=\"fill: #000; stroke-width: 0px;\"/>\n</svg>";
|
|
1363
|
+
//#endregion
|
|
1364
|
+
//#region src/icons/stonecrop-ui-icon-insert-above.svg?raw
|
|
1365
|
+
var stonecrop_ui_icon_insert_above_default = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<svg id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 70.6 61.5\">\n <path d=\"M68.6,45.8v13.7H2v-13.7h66.6M70.6,43.8H0v17.7h70.6v-17.7h0Z\"/>\n <path d=\"M68.6,24.2v13.7H2v-13.7h66.6M70.6,22.2H0v17.7h70.6v-17.7h0Z\"/>\n <g>\n <polygon points=\"70.6 2.5 68.6 2.5 68.6 2 68.1 2 68.1 0 70.6 0 70.6 2.5\"/>\n <path d=\"M65.3,2h-2.9V0h2.9v2ZM59.6,2h-2.9V0h2.9v2ZM53.9,2h-2.9V0h2.9v2ZM48.2,2h-2.9V0h2.9v2ZM42.4,2h-2.9V0h2.9v2ZM36.7,2h-2.9V0h2.9v2ZM31,2h-2.9V0h2.9v2ZM25.3,2h-2.9V0h2.9v2ZM19.6,2h-2.9V0h2.9v2ZM13.9,2h-2.9V0h2.9v2ZM8.2,2h-2.9V0h2.9v2Z\"/>\n <polygon points=\"2 2.5 0 2.5 0 0 2.5 0 2.5 2 2 2 2 2.5\"/>\n <path d=\"M2,13.4H0v-2.7h2v2.7ZM2,8H0v-2.7h2v2.7Z\"/>\n <polygon points=\"2.5 18.7 0 18.7 0 16.2 2 16.2 2 16.7 2.5 16.7 2.5 18.7\"/>\n <path d=\"M65.3,18.7h-2.9v-2h2.9v2ZM59.6,18.7h-2.9v-2h2.9v2ZM53.9,18.7h-2.9v-2h2.9v2ZM48.2,18.7h-2.9v-2h2.9v2ZM42.4,18.7h-2.9v-2h2.9v2ZM36.7,18.7h-2.9v-2h2.9v2ZM31,18.7h-2.9v-2h2.9v2ZM25.3,18.7h-2.9v-2h2.9v2ZM19.6,18.7h-2.9v-2h2.9v2ZM13.9,18.7h-2.9v-2h2.9v2ZM8.2,18.7h-2.9v-2h2.9v2Z\"/>\n <polygon points=\"70.6 18.7 68.1 18.7 68.1 16.7 68.6 16.7 68.6 16.2 70.6 16.2 70.6 18.7\"/>\n <path d=\"M70.6,13.4h-2v-2.7h2v2.7ZM70.6,8h-2v-2.7h2v2.7Z\"/>\n </g>\n</svg>";
|
|
1366
|
+
//#endregion
|
|
1367
|
+
//#region src/icons/stonecrop-ui-icon-insert-below.svg?raw
|
|
1368
|
+
var stonecrop_ui_icon_insert_below_default = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<svg id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 70.6 61.5\">\n <g>\n <polygon points=\"70.6 45.3 68.6 45.3 68.6 44.8 68.1 44.8 68.1 42.8 70.6 42.8 70.6 45.3\"/>\n <path d=\"M65.3,44.8h-2.9v-2h2.9v2ZM59.6,44.8h-2.9v-2h2.9v2ZM53.9,44.8h-2.9v-2h2.9v2ZM48.2,44.8h-2.9v-2h2.9v2ZM42.4,44.8h-2.9v-2h2.9v2ZM36.7,44.8h-2.9v-2h2.9v2ZM31,44.8h-2.9v-2h2.9v2ZM25.3,44.8h-2.9v-2h2.9v2ZM19.6,44.8h-2.9v-2h2.9v2ZM13.9,44.8h-2.9v-2h2.9v2ZM8.2,44.8h-2.9v-2h2.9v2Z\"/>\n <polygon points=\"2 45.3 0 45.3 0 42.8 2.5 42.8 2.5 44.8 2 44.8 2 45.3\"/>\n <path d=\"M2,56.3H0v-2.7h2v2.7ZM2,50.8H0v-2.7h2v2.7Z\"/>\n <polygon points=\"2.5 61.5 0 61.5 0 59 2 59 2 59.5 2.5 59.5 2.5 61.5\"/>\n <path d=\"M65.3,61.5h-2.9v-2h2.9v2ZM59.6,61.5h-2.9v-2h2.9v2ZM53.9,61.5h-2.9v-2h2.9v2ZM48.2,61.5h-2.9v-2h2.9v2ZM42.4,61.5h-2.9v-2h2.9v2ZM36.7,61.5h-2.9v-2h2.9v2ZM31,61.5h-2.9v-2h2.9v2ZM25.3,61.5h-2.9v-2h2.9v2ZM19.6,61.5h-2.9v-2h2.9v2ZM13.9,61.5h-2.9v-2h2.9v2ZM8.2,61.5h-2.9v-2h2.9v2Z\"/>\n <polygon points=\"70.6 61.5 68.1 61.5 68.1 59.5 68.6 59.5 68.6 59 70.6 59 70.6 61.5\"/>\n <path d=\"M70.6,56.3h-2v-2.7h2v2.7ZM70.6,50.8h-2v-2.7h2v2.7Z\"/>\n </g>\n <path d=\"M68.6,23.7v13.7H2v-13.7h66.6M70.6,21.7H0v17.7h70.6v-17.7h0Z\"/>\n <path d=\"M68.6,2v13.7H2V2h66.6M70.6,0H0v17.7h70.6V0h0Z\"/>\n</svg>";
|
|
1369
|
+
//#endregion
|
|
1370
|
+
//#region src/icons/stonecrop-ui-icon-move.svg?raw
|
|
1371
|
+
var stonecrop_ui_icon_move_default = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<svg id=\"Layer_1\" data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 70.67 70.64\">\n <path d=\"M70.08,33.9l-9.75-9.75-2.83,2.83,6.33,6.33h-26.51V6.81l6.33,6.33,2.83-2.83L36.75.56c-.75-.75-2.08-.75-2.83,0l-9.75,9.75,2.83,2.83,6.33-6.33v26.5H6.83l6.33-6.33-2.83-2.83L.59,33.9c-.38.38-.59.88-.59,1.41s.21,1.04.59,1.41l9.75,9.75,2.83-2.83-6.33-6.33h26.5v26.51l-6.33-6.33-2.83,2.83,9.75,9.75c.38.38.88.59,1.41.59s1.04-.21,1.41-.59l9.75-9.75-2.83-2.83-6.33,6.33v-26.51h26.51l-6.33,6.33,2.83,2.83,9.75-9.75c.38-.38.59-.88.59-1.41s-.21-1.04-.59-1.41Z\" style=\"fill: #000; stroke-width: 0px;\"/>\n</svg>";
|
|
1372
|
+
//#endregion
|
|
1373
|
+
//#region src/icons/stonecrop-ui-icon-open.svg?raw
|
|
1374
|
+
var stonecrop_ui_icon_open_default = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<svg id=\"Layer_1\" data-name=\"Layer 1\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\">\n <path d=\"M32,64C14.35,64,0,49.65,0,32S14.35,0,32,0s32,14.35,32,32-14.35,32-32,32ZM32,4c-15.44,0-28,12.56-28,28s12.56,28,28,28,28-12.56,28-28S47.44,4,32,4Z\" style=\"fill: #000; stroke-width: 0px;\"/>\n <polygon points=\"18,20 18,44 46,32\" style=\"fill: #000; stroke-width: 0px;\"/>\n</svg>\n";
|
|
1375
|
+
//#endregion
|
|
1376
|
+
//#region src/icons/index.ts
|
|
1377
|
+
/**
|
|
1378
|
+
* Icon exports for ATable row actions.
|
|
1379
|
+
* Icons are exported as raw SVG strings for flexibility in rendering.
|
|
1380
|
+
* @packageDocumentation
|
|
1381
|
+
*/
|
|
1382
|
+
/** Raw SVG for the add-row action. @public */
|
|
1383
|
+
var AddIcon = stonecrop_ui_icon_add_default;
|
|
1384
|
+
/** Raw SVG for the delete-row action. @public */
|
|
1385
|
+
var DeleteIcon = stonecrop_ui_icon_delete_default;
|
|
1386
|
+
/** Raw SVG for the duplicate-row action. @public */
|
|
1387
|
+
var DuplicateIcon = stonecrop_ui_icon_duplicate_default;
|
|
1388
|
+
/** Raw SVG for the insert-above action. @public */
|
|
1389
|
+
var InsertAboveIcon = stonecrop_ui_icon_insert_above_default;
|
|
1390
|
+
/** Raw SVG for the insert-below action. @public */
|
|
1391
|
+
var InsertBelowIcon = stonecrop_ui_icon_insert_below_default;
|
|
1392
|
+
/** Raw SVG for the move action. @public */
|
|
1393
|
+
var MoveIcon = stonecrop_ui_icon_move_default;
|
|
1394
|
+
/** Raw SVG for the open-record action. @public */
|
|
1395
|
+
var OpenIcon = stonecrop_ui_icon_open_default;
|
|
1396
|
+
/**
|
|
1397
|
+
* Map of action types to their default icons.
|
|
1398
|
+
*
|
|
1399
|
+
* @public
|
|
1400
|
+
*/
|
|
1401
|
+
var actionIcons = {
|
|
1402
|
+
add: AddIcon,
|
|
1403
|
+
delete: DeleteIcon,
|
|
1404
|
+
duplicate: DuplicateIcon,
|
|
1405
|
+
insertAbove: InsertAboveIcon,
|
|
1406
|
+
insertBelow: InsertBelowIcon,
|
|
1407
|
+
move: MoveIcon,
|
|
1408
|
+
moveUp: "<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M8 13V3.5M4.5 7 8 3.5 11.5 7\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>",
|
|
1409
|
+
moveDown: "<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M8 3v9.5M4.5 9 8 12.5 11.5 9\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>",
|
|
1410
|
+
open: OpenIcon
|
|
1411
|
+
};
|
|
1412
|
+
//#endregion
|
|
1413
|
+
//#region src/components/ARowActions.vue?vue&type=script&setup=true&lang.ts
|
|
1414
|
+
var _hoisted_1$8 = {
|
|
1415
|
+
key: 0,
|
|
1416
|
+
class: "row-actions-dropdown"
|
|
1417
|
+
};
|
|
1418
|
+
var _hoisted_2$7 = ["aria-expanded"];
|
|
1419
|
+
var _hoisted_3$5 = ["disabled", "onClick"];
|
|
1420
|
+
var _hoisted_4$4 = ["innerHTML"];
|
|
1421
|
+
var _hoisted_5$2 = { class: "action-label" };
|
|
1422
|
+
var _hoisted_6$2 = {
|
|
1423
|
+
key: 1,
|
|
1424
|
+
class: "row-actions-icons"
|
|
1425
|
+
};
|
|
1426
|
+
var _hoisted_7$2 = [
|
|
1427
|
+
"title",
|
|
1428
|
+
"aria-label",
|
|
1429
|
+
"disabled",
|
|
1430
|
+
"onClick"
|
|
1431
|
+
];
|
|
1432
|
+
var _hoisted_8$1 = ["innerHTML"];
|
|
1433
|
+
//#endregion
|
|
1434
|
+
//#region src/components/ARowActions.vue
|
|
1435
|
+
var ARowActions_default = /* @__PURE__ */ defineComponent({
|
|
1436
|
+
__name: "ARowActions",
|
|
1437
|
+
props: {
|
|
1438
|
+
rowIndex: {},
|
|
1439
|
+
store: {},
|
|
1440
|
+
config: {},
|
|
1441
|
+
position: {}
|
|
1442
|
+
},
|
|
1443
|
+
emits: ["action"],
|
|
1444
|
+
setup(__props, { emit: __emit }) {
|
|
1445
|
+
const props = __props;
|
|
1446
|
+
const emit = __emit;
|
|
1447
|
+
const actionsCellRef = useTemplateRef("actionsCell");
|
|
1448
|
+
const toggleButtonRef = useTemplateRef("toggleButton");
|
|
1449
|
+
const cellWidth = ref(0);
|
|
1450
|
+
const dropdownOpen = ref(false);
|
|
1451
|
+
const dropdownFlipped = ref(false);
|
|
1452
|
+
const menuPosition = ref({
|
|
1453
|
+
top: 0,
|
|
1454
|
+
left: 0
|
|
1455
|
+
});
|
|
1456
|
+
const defaultLabels = {
|
|
1457
|
+
add: "Add Record",
|
|
1458
|
+
delete: "Delete Record",
|
|
1459
|
+
duplicate: "Duplicate Record",
|
|
1460
|
+
insertAbove: "Insert Above",
|
|
1461
|
+
insertBelow: "Insert Below",
|
|
1462
|
+
move: "Move Record",
|
|
1463
|
+
moveUp: "Move Up",
|
|
1464
|
+
moveDown: "Move Down",
|
|
1465
|
+
open: "Open Record"
|
|
1466
|
+
};
|
|
1467
|
+
const enabledActions = computed(() => {
|
|
1468
|
+
const actions = [];
|
|
1469
|
+
const configActions = props.config.actions || {};
|
|
1470
|
+
for (const type of [
|
|
1471
|
+
"open",
|
|
1472
|
+
"moveUp",
|
|
1473
|
+
"moveDown",
|
|
1474
|
+
"duplicate",
|
|
1475
|
+
"insertAbove",
|
|
1476
|
+
"insertBelow",
|
|
1477
|
+
"add",
|
|
1478
|
+
"delete",
|
|
1479
|
+
"move"
|
|
1480
|
+
]) {
|
|
1481
|
+
const actionConfig = configActions[type];
|
|
1482
|
+
if (actionConfig === false) continue;
|
|
1483
|
+
if (actionConfig === void 0) continue;
|
|
1484
|
+
let enabled = true;
|
|
1485
|
+
let label = defaultLabels[type];
|
|
1486
|
+
let icon = actionIcons[type];
|
|
1487
|
+
let disabled = false;
|
|
1488
|
+
if (typeof actionConfig === "object") {
|
|
1489
|
+
enabled = actionConfig.enabled !== false;
|
|
1490
|
+
label = actionConfig.label || label;
|
|
1491
|
+
icon = actionConfig.icon || icon;
|
|
1492
|
+
if (actionConfig.disabled) disabled = actionConfig.disabled(props.rowIndex, props.store);
|
|
1493
|
+
}
|
|
1494
|
+
if (enabled) actions.push({
|
|
1495
|
+
type,
|
|
1496
|
+
label,
|
|
1497
|
+
icon,
|
|
1498
|
+
disabled
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1501
|
+
return actions;
|
|
1502
|
+
});
|
|
1503
|
+
const showDropdown = computed(() => {
|
|
1504
|
+
if (props.config.forceDropdown) return true;
|
|
1505
|
+
const threshold = props.config.dropdownThreshold ?? 150;
|
|
1506
|
+
if (threshold === 0) return false;
|
|
1507
|
+
return cellWidth.value > 0 && cellWidth.value < threshold;
|
|
1508
|
+
});
|
|
1509
|
+
const menuStyle = computed(() => {
|
|
1510
|
+
if (!dropdownOpen.value) return {};
|
|
1511
|
+
if (dropdownFlipped.value) return {
|
|
1512
|
+
position: "fixed",
|
|
1513
|
+
bottom: `${window.innerHeight - menuPosition.value.top}px`,
|
|
1514
|
+
left: `${menuPosition.value.left}px`,
|
|
1515
|
+
top: "auto"
|
|
1516
|
+
};
|
|
1517
|
+
return {
|
|
1518
|
+
position: "fixed",
|
|
1519
|
+
top: `${menuPosition.value.top}px`,
|
|
1520
|
+
left: `${menuPosition.value.left}px`
|
|
1521
|
+
};
|
|
1522
|
+
});
|
|
1523
|
+
useResizeObserver(actionsCellRef, (entries) => {
|
|
1524
|
+
const entry = entries[0];
|
|
1525
|
+
if (entry) cellWidth.value = entry.contentRect.width;
|
|
1526
|
+
});
|
|
1527
|
+
const toggleDropdown = () => {
|
|
1528
|
+
if (!dropdownOpen.value) checkDropdownPosition();
|
|
1529
|
+
dropdownOpen.value = !dropdownOpen.value;
|
|
1530
|
+
};
|
|
1531
|
+
const checkDropdownPosition = () => {
|
|
1532
|
+
if (!toggleButtonRef.value) return;
|
|
1533
|
+
const buttonRect = toggleButtonRef.value.getBoundingClientRect();
|
|
1534
|
+
const viewportHeight = window.innerHeight;
|
|
1535
|
+
const viewportWidth = window.innerWidth;
|
|
1536
|
+
const estimatedMenuHeight = enabledActions.value.length * 40 + 16;
|
|
1537
|
+
const estimatedMenuWidth = 160;
|
|
1538
|
+
const spaceBelow = viewportHeight - buttonRect.bottom;
|
|
1539
|
+
const spaceAbove = buttonRect.top;
|
|
1540
|
+
dropdownFlipped.value = spaceBelow < estimatedMenuHeight && spaceAbove > estimatedMenuHeight;
|
|
1541
|
+
let left = buttonRect.left;
|
|
1542
|
+
if (left + estimatedMenuWidth > viewportWidth) left = Math.max(0, buttonRect.right - estimatedMenuWidth);
|
|
1543
|
+
menuPosition.value = {
|
|
1544
|
+
top: dropdownFlipped.value ? buttonRect.top : buttonRect.bottom,
|
|
1545
|
+
left
|
|
1546
|
+
};
|
|
1547
|
+
};
|
|
1548
|
+
onClickOutside(actionsCellRef, () => {
|
|
1549
|
+
dropdownOpen.value = false;
|
|
1550
|
+
});
|
|
1551
|
+
const executeAction = (actionType, event) => {
|
|
1552
|
+
dropdownOpen.value = false;
|
|
1553
|
+
const actionConfig = props.config.actions?.[actionType];
|
|
1554
|
+
if (typeof actionConfig === "object" && actionConfig.handler) {
|
|
1555
|
+
if (actionConfig.handler(props.rowIndex, props.store) === false) return;
|
|
1556
|
+
}
|
|
1557
|
+
emit("action", actionType, props.rowIndex, event);
|
|
1558
|
+
};
|
|
1559
|
+
return (_ctx, _cache) => {
|
|
1560
|
+
return openBlock(), createElementBlock("td", {
|
|
1561
|
+
ref: "actionsCell",
|
|
1562
|
+
class: normalizeClass(["atable-row-actions", {
|
|
1563
|
+
"sticky-column": __props.position === "before-index",
|
|
1564
|
+
"dropdown-active": dropdownOpen.value
|
|
1565
|
+
}])
|
|
1566
|
+
}, [showDropdown.value ? (openBlock(), createElementBlock("div", _hoisted_1$8, [createElementVNode("button", {
|
|
1567
|
+
ref: "toggleButton",
|
|
1568
|
+
type: "button",
|
|
1569
|
+
class: "row-actions-toggle",
|
|
1570
|
+
"aria-expanded": dropdownOpen.value,
|
|
1571
|
+
"aria-haspopup": "true",
|
|
1572
|
+
onClick: withModifiers(toggleDropdown, ["stop"])
|
|
1573
|
+
}, [..._cache[0] || (_cache[0] = [createElementVNode("span", { class: "dropdown-icon" }, "⋮", -1)])], 8, _hoisted_2$7), withDirectives(createElementVNode("div", {
|
|
1574
|
+
class: normalizeClass(["row-actions-menu", { "menu-flipped": dropdownFlipped.value }]),
|
|
1575
|
+
style: normalizeStyle(menuStyle.value),
|
|
1576
|
+
role: "menu"
|
|
1577
|
+
}, [(openBlock(true), createElementBlock(Fragment, null, renderList(enabledActions.value, (action) => {
|
|
1578
|
+
return openBlock(), createElementBlock("button", {
|
|
1579
|
+
key: action.type,
|
|
1580
|
+
type: "button",
|
|
1581
|
+
class: "row-action-menu-item",
|
|
1582
|
+
role: "menuitem",
|
|
1583
|
+
disabled: action.disabled,
|
|
1584
|
+
onClick: withModifiers(($event) => executeAction(action.type, $event), ["stop"])
|
|
1585
|
+
}, [createElementVNode("span", {
|
|
1586
|
+
class: "action-icon",
|
|
1587
|
+
innerHTML: action.icon
|
|
1588
|
+
}, null, 8, _hoisted_4$4), createElementVNode("span", _hoisted_5$2, toDisplayString(action.label), 1)], 8, _hoisted_3$5);
|
|
1589
|
+
}), 128))], 6), [[vShow, dropdownOpen.value]])])) : (openBlock(), createElementBlock("div", _hoisted_6$2, [(openBlock(true), createElementBlock(Fragment, null, renderList(enabledActions.value, (action) => {
|
|
1590
|
+
return openBlock(), createElementBlock("button", {
|
|
1591
|
+
key: action.type,
|
|
1592
|
+
type: "button",
|
|
1593
|
+
class: "row-action-btn",
|
|
1594
|
+
title: action.label,
|
|
1595
|
+
"aria-label": action.label,
|
|
1596
|
+
disabled: action.disabled,
|
|
1597
|
+
onClick: withModifiers(($event) => executeAction(action.type, $event), ["stop"])
|
|
1598
|
+
}, [createElementVNode("span", {
|
|
1599
|
+
class: "action-icon",
|
|
1600
|
+
innerHTML: action.icon
|
|
1601
|
+
}, null, 8, _hoisted_8$1)], 8, _hoisted_7$2);
|
|
1602
|
+
}), 128))]))], 2);
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1605
|
+
});
|
|
1606
|
+
//#endregion
|
|
1607
|
+
//#region src/components/ARow.vue?vue&type=script&setup=true&lang.ts
|
|
1608
|
+
var _hoisted_1$7 = ["tabindex"];
|
|
1609
|
+
var _hoisted_2$6 = ["tabindex"];
|
|
1610
|
+
var _hoisted_3$4 = ["colspan"];
|
|
1611
|
+
//#endregion
|
|
1612
|
+
//#region src/components/ARow.vue
|
|
1613
|
+
var ARow_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
1614
|
+
__name: "ARow",
|
|
1615
|
+
props: {
|
|
1616
|
+
rowIndex: {},
|
|
1617
|
+
store: {},
|
|
1618
|
+
tabIndex: { default: () => -1 },
|
|
1619
|
+
addNavigation: {
|
|
1620
|
+
type: [Boolean, Object],
|
|
1621
|
+
default: false
|
|
1622
|
+
}
|
|
1623
|
+
},
|
|
1624
|
+
emits: ["row:action", "row:click"],
|
|
1625
|
+
setup(__props, { emit: __emit }) {
|
|
1626
|
+
const emit = __emit;
|
|
1627
|
+
const rowRef = useTemplateRef("rowEl");
|
|
1628
|
+
const isRowVisible = computed(() => __props.store.isRowVisible(__props.rowIndex));
|
|
1629
|
+
const rowExpandSymbol = computed(() => __props.store.getRowExpandSymbol(__props.rowIndex));
|
|
1630
|
+
const isClickable = computed(() => __props.store.config.clickable ?? false);
|
|
1631
|
+
const rowActionsConfig = computed(() => {
|
|
1632
|
+
return __props.store.config.rowActions || { enabled: false };
|
|
1633
|
+
});
|
|
1634
|
+
const showRowActions = computed(() => {
|
|
1635
|
+
return rowActionsConfig.value.enabled;
|
|
1636
|
+
});
|
|
1637
|
+
const actionsPosition = computed(() => {
|
|
1638
|
+
return rowActionsConfig.value.position || "before-index";
|
|
1639
|
+
});
|
|
1640
|
+
const isExpanded = computed(() => __props.store.config.view === "list-expansion" && Boolean(__props.store.display[__props.rowIndex]?.expanded));
|
|
1641
|
+
const expandedColspan = computed(() => {
|
|
1642
|
+
const indexCol = __props.store.config.view === "uncounted" ? 0 : 1;
|
|
1643
|
+
const actionsCol = showRowActions.value ? 1 : 0;
|
|
1644
|
+
return __props.store.columns.length + indexCol + actionsCol;
|
|
1645
|
+
});
|
|
1646
|
+
const onRowAction = (actionType, index, event) => {
|
|
1647
|
+
emit("row:action", actionType, index, event);
|
|
1648
|
+
};
|
|
1649
|
+
const onRowClick = (event) => {
|
|
1650
|
+
const target = event.target;
|
|
1651
|
+
if (target.closest(".atable-row-actions") || target.closest(".tree-index") || target.closest(".expansion-index")) return;
|
|
1652
|
+
emit("row:click", __props.rowIndex, event);
|
|
1653
|
+
};
|
|
1654
|
+
const isListExpansion = __props.store.config.view === "list-expansion";
|
|
1655
|
+
if (__props.addNavigation || isListExpansion) {
|
|
1656
|
+
let handlers = {};
|
|
1657
|
+
if (__props.addNavigation === true) handlers = { ...defaultKeypressHandlers };
|
|
1658
|
+
else if (typeof __props.addNavigation === "object") handlers = {
|
|
1659
|
+
...defaultKeypressHandlers,
|
|
1660
|
+
...__props.addNavigation
|
|
1661
|
+
};
|
|
1662
|
+
if (isListExpansion && !handlers["keydown.control.g"]) handlers["keydown.control.g"] = (event) => {
|
|
1663
|
+
event.stopPropagation();
|
|
1664
|
+
event.preventDefault();
|
|
1665
|
+
__props.store.toggleRowExpand(__props.rowIndex);
|
|
1666
|
+
};
|
|
1667
|
+
useKeyboardNav([{
|
|
1668
|
+
selectors: rowRef,
|
|
1669
|
+
handlers
|
|
1670
|
+
}]);
|
|
1671
|
+
}
|
|
1672
|
+
return (_ctx, _cache) => {
|
|
1673
|
+
return openBlock(), createElementBlock(Fragment, null, [withDirectives(createElementVNode("tr", mergeProps(_ctx.$attrs, {
|
|
1674
|
+
ref: "rowEl",
|
|
1675
|
+
tabindex: __props.tabIndex,
|
|
1676
|
+
class: ["atable-row", { "atable-row-clickable": isClickable.value }],
|
|
1677
|
+
onClick: onRowClick
|
|
1678
|
+
}), [
|
|
1679
|
+
showRowActions.value && actionsPosition.value === "before-index" ? (openBlock(), createBlock(ARowActions_default, {
|
|
1680
|
+
key: 0,
|
|
1681
|
+
"row-index": __props.rowIndex,
|
|
1682
|
+
store: __props.store,
|
|
1683
|
+
config: rowActionsConfig.value,
|
|
1684
|
+
position: actionsPosition.value,
|
|
1685
|
+
onAction: onRowAction
|
|
1686
|
+
}, null, 8, [
|
|
1687
|
+
"row-index",
|
|
1688
|
+
"store",
|
|
1689
|
+
"config",
|
|
1690
|
+
"position"
|
|
1691
|
+
])) : createCommentVNode("", true),
|
|
1692
|
+
__props.store.config.view !== "uncounted" ? renderSlot(_ctx.$slots, "index", {}, () => [__props.store.config.view === "list" ? (openBlock(), createElementBlock("td", {
|
|
1693
|
+
key: 0,
|
|
1694
|
+
tabIndex: -1,
|
|
1695
|
+
class: normalizeClass(["list-index", __props.store.hasPinnedColumns ? "sticky-index" : ""])
|
|
1696
|
+
}, toDisplayString(__props.rowIndex + 1), 3)) : __props.store.isTreeView ? (openBlock(), createElementBlock("td", {
|
|
1697
|
+
key: 1,
|
|
1698
|
+
tabIndex: -1,
|
|
1699
|
+
class: normalizeClass(["tree-index", __props.store.hasPinnedColumns ? "sticky-index" : ""]),
|
|
1700
|
+
onClick: _cache[0] || (_cache[0] = ($event) => __props.store.toggleRowExpand(__props.rowIndex))
|
|
1701
|
+
}, toDisplayString(rowExpandSymbol.value), 3)) : __props.store.config.view === "list-expansion" ? (openBlock(), createElementBlock("td", {
|
|
1702
|
+
key: 2,
|
|
1703
|
+
tabIndex: -1,
|
|
1704
|
+
class: normalizeClass(["expansion-index", __props.store.hasPinnedColumns ? "sticky-index" : ""]),
|
|
1705
|
+
onClick: _cache[1] || (_cache[1] = ($event) => __props.store.toggleRowExpand(__props.rowIndex))
|
|
1706
|
+
}, toDisplayString(rowExpandSymbol.value), 3)) : createCommentVNode("", true)], true, 1) : createCommentVNode("", true),
|
|
1707
|
+
showRowActions.value && actionsPosition.value === "after-index" ? (openBlock(), createBlock(ARowActions_default, {
|
|
1708
|
+
key: 2,
|
|
1709
|
+
"row-index": __props.rowIndex,
|
|
1710
|
+
store: __props.store,
|
|
1711
|
+
config: rowActionsConfig.value,
|
|
1712
|
+
position: actionsPosition.value,
|
|
1713
|
+
onAction: onRowAction
|
|
1714
|
+
}, null, 8, [
|
|
1715
|
+
"row-index",
|
|
1716
|
+
"store",
|
|
1717
|
+
"config",
|
|
1718
|
+
"position"
|
|
1719
|
+
])) : createCommentVNode("", true),
|
|
1720
|
+
renderSlot(_ctx.$slots, "default", {}, void 0, true),
|
|
1721
|
+
showRowActions.value && actionsPosition.value === "end" ? (openBlock(), createBlock(ARowActions_default, {
|
|
1722
|
+
key: 3,
|
|
1723
|
+
"row-index": __props.rowIndex,
|
|
1724
|
+
store: __props.store,
|
|
1725
|
+
config: rowActionsConfig.value,
|
|
1726
|
+
position: actionsPosition.value,
|
|
1727
|
+
onAction: onRowAction
|
|
1728
|
+
}, null, 8, [
|
|
1729
|
+
"row-index",
|
|
1730
|
+
"store",
|
|
1731
|
+
"config",
|
|
1732
|
+
"position"
|
|
1733
|
+
])) : createCommentVNode("", true)
|
|
1734
|
+
], 16, _hoisted_1$7), [[vShow, isRowVisible.value]]), isExpanded.value ? (openBlock(), createElementBlock("tr", {
|
|
1735
|
+
key: 0,
|
|
1736
|
+
tabindex: __props.tabIndex,
|
|
1737
|
+
class: "atable-expanded-row"
|
|
1738
|
+
}, [createElementVNode("td", {
|
|
1739
|
+
tabIndex: -1,
|
|
1740
|
+
colspan: expandedColspan.value,
|
|
1741
|
+
class: "atable-expanded-content"
|
|
1742
|
+
}, [renderSlot(_ctx.$slots, "content", {
|
|
1743
|
+
row: __props.store.rows[__props.rowIndex],
|
|
1744
|
+
rowIndex: __props.rowIndex,
|
|
1745
|
+
store: __props.store
|
|
1746
|
+
}, void 0, true)], 8, _hoisted_3$4)], 8, _hoisted_2$6)) : createCommentVNode("", true)], 64);
|
|
1747
|
+
};
|
|
1748
|
+
}
|
|
1749
|
+
}), [["__scopeId", "data-v-f159cfbe"]]);
|
|
1750
|
+
//#endregion
|
|
1751
|
+
//#region src/components/AGanttConnection.vue?vue&type=script&setup=true&lang.ts
|
|
1752
|
+
var _hoisted_1$6 = { class: "gantt-connection-overlay" };
|
|
1753
|
+
var _hoisted_2$5 = {
|
|
1754
|
+
class: "connection-svg",
|
|
1755
|
+
style: {
|
|
1756
|
+
position: "absolute",
|
|
1757
|
+
top: 0,
|
|
1758
|
+
left: 0,
|
|
1759
|
+
width: "100%",
|
|
1760
|
+
height: "100%",
|
|
1761
|
+
pointerEvents: "none",
|
|
1762
|
+
zIndex: 1
|
|
1763
|
+
}
|
|
1764
|
+
};
|
|
1765
|
+
var _hoisted_3$3 = [
|
|
1766
|
+
"d",
|
|
1767
|
+
"stroke-width",
|
|
1768
|
+
"onDblclick"
|
|
1769
|
+
];
|
|
1770
|
+
var _hoisted_4$3 = [
|
|
1771
|
+
"id",
|
|
1772
|
+
"d",
|
|
1773
|
+
"stroke",
|
|
1774
|
+
"stroke-width",
|
|
1775
|
+
"onDblclick"
|
|
1776
|
+
];
|
|
1777
|
+
var BEZIER_CURVE_FACTOR = .25;
|
|
1778
|
+
var CONNECTION_HANDLE_SIZE = 16;
|
|
1779
|
+
//#endregion
|
|
1780
|
+
//#region src/components/AGanttConnection.vue
|
|
1781
|
+
var AGanttConnection_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
1782
|
+
__name: "AGanttConnection",
|
|
1783
|
+
props: { store: {} },
|
|
1784
|
+
emits: ["connection:delete"],
|
|
1785
|
+
setup(__props, { emit: __emit }) {
|
|
1786
|
+
const emit = __emit;
|
|
1787
|
+
const visibleConnections = computed(() => {
|
|
1788
|
+
return __props.store.connectionPaths.filter((connection) => {
|
|
1789
|
+
const fromBar = __props.store.ganttBars.find((bar) => bar.id === connection.from.barId);
|
|
1790
|
+
const toBar = __props.store.ganttBars.find((bar) => bar.id === connection.to.barId);
|
|
1791
|
+
return fromBar && toBar;
|
|
1792
|
+
});
|
|
1793
|
+
});
|
|
1794
|
+
const getPathData = (connection) => {
|
|
1795
|
+
const fromHandle = __props.store.connectionHandles.find((handle) => handle.barId === connection.from.barId && handle.side === connection.from.side);
|
|
1796
|
+
const toHandle = __props.store.connectionHandles.find((handle) => handle.barId === connection.to.barId && handle.side === connection.to.side);
|
|
1797
|
+
if (!fromHandle || !toHandle) return "";
|
|
1798
|
+
const fromX = fromHandle.position.x + CONNECTION_HANDLE_SIZE / 2;
|
|
1799
|
+
const fromY = fromHandle.position.y + CONNECTION_HANDLE_SIZE / 2;
|
|
1800
|
+
const toX = toHandle.position.x + CONNECTION_HANDLE_SIZE / 2;
|
|
1801
|
+
const toY = toHandle.position.y + CONNECTION_HANDLE_SIZE / 2;
|
|
1802
|
+
const deltaX = Math.abs(toX - fromX);
|
|
1803
|
+
const controlPointOffset = Math.max(deltaX * BEZIER_CURVE_FACTOR, 50);
|
|
1804
|
+
const cp1X = fromX + (connection.from.side === "left" ? -controlPointOffset : controlPointOffset);
|
|
1805
|
+
const cp2X = toX + (connection.to.side === "left" ? -controlPointOffset : controlPointOffset);
|
|
1806
|
+
const m0 = {
|
|
1807
|
+
x: .5 * fromX + .5 * cp1X,
|
|
1808
|
+
y: .5 * fromY + .5 * fromY
|
|
1809
|
+
};
|
|
1810
|
+
const m1 = {
|
|
1811
|
+
x: .5 * cp1X + .5 * cp2X,
|
|
1812
|
+
y: .5 * fromY + .5 * toY
|
|
1813
|
+
};
|
|
1814
|
+
const m2 = {
|
|
1815
|
+
x: .5 * cp2X + .5 * toX,
|
|
1816
|
+
y: .5 * toY + .5 * toY
|
|
1817
|
+
};
|
|
1818
|
+
const m3 = {
|
|
1819
|
+
x: .5 * m0.x + .5 * m1.x,
|
|
1820
|
+
y: .5 * m0.y + .5 * m1.y
|
|
1821
|
+
};
|
|
1822
|
+
const m4 = {
|
|
1823
|
+
x: .5 * m1.x + .5 * m2.x,
|
|
1824
|
+
y: .5 * m1.y + .5 * m2.y
|
|
1825
|
+
};
|
|
1826
|
+
const midpoint = {
|
|
1827
|
+
x: .5 * m3.x + .5 * m4.x,
|
|
1828
|
+
y: .5 * m3.y + .5 * m4.y
|
|
1829
|
+
};
|
|
1830
|
+
return `M ${fromX} ${fromY} Q ${cp1X} ${fromY}, ${midpoint.x} ${midpoint.y} Q ${cp2X} ${toY}, ${toX} ${toY}`;
|
|
1831
|
+
};
|
|
1832
|
+
const handleConnectionDelete = (connection) => {
|
|
1833
|
+
if (__props.store.deleteConnection(connection.id)) emit("connection:delete", connection);
|
|
1834
|
+
};
|
|
1835
|
+
return (_ctx, _cache) => {
|
|
1836
|
+
return openBlock(), createElementBlock("div", _hoisted_1$6, [(openBlock(), createElementBlock("svg", _hoisted_2$5, [
|
|
1837
|
+
_cache[0] || (_cache[0] = createElementVNode("defs", null, [createElementVNode("path", {
|
|
1838
|
+
id: "arrowhead",
|
|
1839
|
+
d: "M 0 -7 L 20 0 L 0 7Z",
|
|
1840
|
+
stroke: "black",
|
|
1841
|
+
"stroke-width": "1",
|
|
1842
|
+
fill: "currentColor"
|
|
1843
|
+
}), createElementVNode("marker", {
|
|
1844
|
+
id: "arrowhead-marker",
|
|
1845
|
+
markerWidth: "10",
|
|
1846
|
+
markerHeight: "7",
|
|
1847
|
+
refX: "5",
|
|
1848
|
+
refY: "3.5",
|
|
1849
|
+
orient: "auto",
|
|
1850
|
+
markerUnits: "strokeWidth"
|
|
1851
|
+
}, [createElementVNode("polygon", {
|
|
1852
|
+
points: "0 0, 10 3.5, 0 7",
|
|
1853
|
+
fill: "currentColor"
|
|
1854
|
+
})])], -1)),
|
|
1855
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(visibleConnections.value, (connection) => {
|
|
1856
|
+
return openBlock(), createElementBlock("path", {
|
|
1857
|
+
key: `${connection.id}-hitbox`,
|
|
1858
|
+
d: getPathData(connection),
|
|
1859
|
+
stroke: "transparent",
|
|
1860
|
+
"stroke-width": (connection.style?.width || 2) + 10,
|
|
1861
|
+
fill: "none",
|
|
1862
|
+
class: "connection-hitbox",
|
|
1863
|
+
onDblclick: ($event) => handleConnectionDelete(connection)
|
|
1864
|
+
}, null, 40, _hoisted_3$3);
|
|
1865
|
+
}), 128)),
|
|
1866
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(visibleConnections.value, (connection) => {
|
|
1867
|
+
return openBlock(), createElementBlock("path", {
|
|
1868
|
+
id: connection.id,
|
|
1869
|
+
key: connection.id,
|
|
1870
|
+
d: getPathData(connection),
|
|
1871
|
+
stroke: connection.style?.color || "#666",
|
|
1872
|
+
"stroke-width": connection.style?.width || 2,
|
|
1873
|
+
fill: "none",
|
|
1874
|
+
"marker-mid": "url(#arrowhead-marker)",
|
|
1875
|
+
class: "connection-path animated-path",
|
|
1876
|
+
onDblclick: ($event) => handleConnectionDelete(connection)
|
|
1877
|
+
}, null, 40, _hoisted_4$3);
|
|
1878
|
+
}), 128))
|
|
1879
|
+
]))]);
|
|
1880
|
+
};
|
|
1881
|
+
}
|
|
1882
|
+
}), [["__scopeId", "data-v-d5929c98"]]);
|
|
1883
|
+
//#endregion
|
|
1884
|
+
//#region src/components/ATableColumnFilter.vue?vue&type=script&setup=true&lang.ts
|
|
1885
|
+
var _hoisted_1$5 = { class: "column-filter" };
|
|
1886
|
+
var _hoisted_2$4 = {
|
|
1887
|
+
key: 2,
|
|
1888
|
+
class: "checkbox-filter"
|
|
1889
|
+
};
|
|
1890
|
+
var _hoisted_3$2 = ["value"];
|
|
1891
|
+
var _hoisted_4$2 = {
|
|
1892
|
+
key: 5,
|
|
1893
|
+
class: "date-range-filter"
|
|
1894
|
+
};
|
|
1895
|
+
//#endregion
|
|
1896
|
+
//#region src/components/ATableColumnFilter.vue
|
|
1897
|
+
var ATableColumnFilter_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
1898
|
+
__name: "ATableColumnFilter",
|
|
1899
|
+
props: {
|
|
1900
|
+
column: {},
|
|
1901
|
+
colIndex: {},
|
|
1902
|
+
store: {}
|
|
1903
|
+
},
|
|
1904
|
+
setup(__props) {
|
|
1905
|
+
const filterValue = ref("");
|
|
1906
|
+
const dateFilter = reactive({
|
|
1907
|
+
startValue: "",
|
|
1908
|
+
endValue: ""
|
|
1909
|
+
});
|
|
1910
|
+
const resolvedFilterType = computed(() => resolveFilterType(__props.column));
|
|
1911
|
+
const getSelectOptions = (col) => {
|
|
1912
|
+
if (col.filterOptions) return col.filterOptions;
|
|
1913
|
+
const uniqueValues = /* @__PURE__ */ new Set();
|
|
1914
|
+
__props.store.rows.forEach((row) => {
|
|
1915
|
+
const value = row[col.name];
|
|
1916
|
+
if (value !== null && value !== void 0 && value !== "") uniqueValues.add(value);
|
|
1917
|
+
});
|
|
1918
|
+
return Array.from(uniqueValues).map((value) => ({
|
|
1919
|
+
value,
|
|
1920
|
+
label: String(value)
|
|
1921
|
+
}));
|
|
1922
|
+
};
|
|
1923
|
+
const hasActiveFilter = computed(() => {
|
|
1924
|
+
return !!(filterValue.value || dateFilter.startValue || dateFilter.endValue);
|
|
1925
|
+
});
|
|
1926
|
+
const updateFilter = (value) => {
|
|
1927
|
+
if (!value && resolvedFilterType.value !== "checkbox") {
|
|
1928
|
+
__props.store.clearFilter(__props.colIndex);
|
|
1929
|
+
filterValue.value = "";
|
|
1930
|
+
} else {
|
|
1931
|
+
filterValue.value = value;
|
|
1932
|
+
__props.store.setFilter(__props.colIndex, { value });
|
|
1933
|
+
}
|
|
1934
|
+
};
|
|
1935
|
+
const updateDateRangeFilter = (rangeType, value) => {
|
|
1936
|
+
if (rangeType === "start") dateFilter.startValue = value;
|
|
1937
|
+
else dateFilter.endValue = value;
|
|
1938
|
+
if (!dateFilter.startValue && !dateFilter.endValue) __props.store.clearFilter(__props.colIndex);
|
|
1939
|
+
else __props.store.setFilter(__props.colIndex, {
|
|
1940
|
+
value: null,
|
|
1941
|
+
startValue: dateFilter.startValue,
|
|
1942
|
+
endValue: dateFilter.endValue
|
|
1943
|
+
});
|
|
1944
|
+
};
|
|
1945
|
+
const clearFilter = () => {
|
|
1946
|
+
filterValue.value = "";
|
|
1947
|
+
dateFilter.startValue = "";
|
|
1948
|
+
dateFilter.endValue = "";
|
|
1949
|
+
__props.store.clearFilter(__props.colIndex);
|
|
1950
|
+
};
|
|
1951
|
+
return (_ctx, _cache) => {
|
|
1952
|
+
return openBlock(), createElementBlock("div", _hoisted_1$5, [resolvedFilterType.value === "text" ? withDirectives((openBlock(), createElementBlock("input", {
|
|
1953
|
+
key: 0,
|
|
1954
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => filterValue.value = $event),
|
|
1955
|
+
type: "text",
|
|
1956
|
+
class: "filter-input",
|
|
1957
|
+
onInput: _cache[1] || (_cache[1] = ($event) => updateFilter(filterValue.value))
|
|
1958
|
+
}, null, 544)), [[vModelText, filterValue.value]]) : resolvedFilterType.value === "number" ? withDirectives((openBlock(), createElementBlock("input", {
|
|
1959
|
+
key: 1,
|
|
1960
|
+
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => filterValue.value = $event),
|
|
1961
|
+
type: "number",
|
|
1962
|
+
class: "filter-input",
|
|
1963
|
+
onInput: _cache[3] || (_cache[3] = ($event) => updateFilter(filterValue.value))
|
|
1964
|
+
}, null, 544)), [[vModelText, filterValue.value]]) : resolvedFilterType.value === "checkbox" ? (openBlock(), createElementBlock("label", _hoisted_2$4, [withDirectives(createElementVNode("input", {
|
|
1965
|
+
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => filterValue.value = $event),
|
|
1966
|
+
type: "checkbox",
|
|
1967
|
+
class: "filter-checkbox",
|
|
1968
|
+
onChange: _cache[5] || (_cache[5] = ($event) => updateFilter(filterValue.value))
|
|
1969
|
+
}, null, 544), [[vModelCheckbox, filterValue.value]]), createElementVNode("span", null, toDisplayString(__props.column.label), 1)])) : resolvedFilterType.value === "select" ? withDirectives((openBlock(), createElementBlock("select", {
|
|
1970
|
+
key: 3,
|
|
1971
|
+
"onUpdate:modelValue": _cache[6] || (_cache[6] = ($event) => filterValue.value = $event),
|
|
1972
|
+
class: "filter-select",
|
|
1973
|
+
onChange: _cache[7] || (_cache[7] = ($event) => updateFilter(filterValue.value))
|
|
1974
|
+
}, [_cache[15] || (_cache[15] = createElementVNode("option", { value: "" }, "All", -1)), (openBlock(true), createElementBlock(Fragment, null, renderList(getSelectOptions(__props.column), (option) => {
|
|
1975
|
+
return openBlock(), createElementBlock("option", {
|
|
1976
|
+
key: option.value || option,
|
|
1977
|
+
value: option.value || option
|
|
1978
|
+
}, toDisplayString(option.label || option), 9, _hoisted_3$2);
|
|
1979
|
+
}), 128))], 544)), [[vModelSelect, filterValue.value]]) : resolvedFilterType.value === "date" ? withDirectives((openBlock(), createElementBlock("input", {
|
|
1980
|
+
key: 4,
|
|
1981
|
+
"onUpdate:modelValue": _cache[8] || (_cache[8] = ($event) => filterValue.value = $event),
|
|
1982
|
+
type: "date",
|
|
1983
|
+
class: "filter-input",
|
|
1984
|
+
onChange: _cache[9] || (_cache[9] = ($event) => updateFilter(filterValue.value))
|
|
1985
|
+
}, null, 544)), [[vModelText, filterValue.value]]) : resolvedFilterType.value === "dateRange" ? (openBlock(), createElementBlock("div", _hoisted_4$2, [
|
|
1986
|
+
withDirectives(createElementVNode("input", {
|
|
1987
|
+
"onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => dateFilter.startValue = $event),
|
|
1988
|
+
type: "date",
|
|
1989
|
+
class: "filter-input",
|
|
1990
|
+
onChange: _cache[11] || (_cache[11] = ($event) => updateDateRangeFilter("start", dateFilter.startValue))
|
|
1991
|
+
}, null, 544), [[vModelText, dateFilter.startValue]]),
|
|
1992
|
+
_cache[16] || (_cache[16] = createElementVNode("span", { class: "date-separator" }, "-", -1)),
|
|
1993
|
+
withDirectives(createElementVNode("input", {
|
|
1994
|
+
"onUpdate:modelValue": _cache[12] || (_cache[12] = ($event) => dateFilter.endValue = $event),
|
|
1995
|
+
type: "date",
|
|
1996
|
+
class: "filter-input",
|
|
1997
|
+
onChange: _cache[13] || (_cache[13] = ($event) => updateDateRangeFilter("end", dateFilter.endValue))
|
|
1998
|
+
}, null, 544), [[vModelText, dateFilter.endValue]])
|
|
1999
|
+
])) : resolvedFilterType.value === "component" && __props.column.filterComponent ? (openBlock(), createBlock(resolveDynamicComponent(__props.column.filterComponent), {
|
|
2000
|
+
key: 6,
|
|
2001
|
+
value: filterValue.value,
|
|
2002
|
+
column: __props.column,
|
|
2003
|
+
"col-index": __props.colIndex,
|
|
2004
|
+
store: __props.store,
|
|
2005
|
+
"onUpdate:value": _cache[14] || (_cache[14] = ($event) => updateFilter($event))
|
|
2006
|
+
}, null, 40, [
|
|
2007
|
+
"value",
|
|
2008
|
+
"column",
|
|
2009
|
+
"col-index",
|
|
2010
|
+
"store"
|
|
2011
|
+
])) : createCommentVNode("", true), hasActiveFilter.value ? (openBlock(), createElementBlock("button", {
|
|
2012
|
+
key: 7,
|
|
2013
|
+
class: "clear-btn",
|
|
2014
|
+
title: "Clear",
|
|
2015
|
+
onClick: clearFilter
|
|
2016
|
+
}, "×")) : createCommentVNode("", true)]);
|
|
2017
|
+
};
|
|
2018
|
+
}
|
|
2019
|
+
}), [["__scopeId", "data-v-f9c23db9"]]);
|
|
2020
|
+
//#endregion
|
|
2021
|
+
//#region src/components/ATableHeader.vue?vue&type=script&setup=true&lang.ts
|
|
2022
|
+
var _hoisted_1$4 = { key: 0 };
|
|
2023
|
+
var _hoisted_2$3 = {
|
|
2024
|
+
class: "atable-header-row",
|
|
2025
|
+
tabindex: "-1"
|
|
2026
|
+
};
|
|
2027
|
+
var _hoisted_3$1 = {
|
|
2028
|
+
key: 2,
|
|
2029
|
+
class: "row-actions-header"
|
|
2030
|
+
};
|
|
2031
|
+
var _hoisted_4$1 = ["data-colindex", "onClick"];
|
|
2032
|
+
var _hoisted_5$1 = {
|
|
2033
|
+
key: 3,
|
|
2034
|
+
class: "row-actions-header"
|
|
2035
|
+
};
|
|
2036
|
+
var _hoisted_6$1 = {
|
|
2037
|
+
key: 0,
|
|
2038
|
+
class: "atable-filters-row"
|
|
2039
|
+
};
|
|
2040
|
+
var _hoisted_7$1 = {
|
|
2041
|
+
key: 2,
|
|
2042
|
+
class: "row-actions-header"
|
|
2043
|
+
};
|
|
2044
|
+
var _hoisted_8 = {
|
|
2045
|
+
key: 3,
|
|
2046
|
+
class: "row-actions-header"
|
|
2047
|
+
};
|
|
2048
|
+
//#endregion
|
|
2049
|
+
//#region src/components/ATableHeader.vue
|
|
2050
|
+
var ATableHeader_default = /* @__PURE__ */ defineComponent({
|
|
2051
|
+
__name: "ATableHeader",
|
|
2052
|
+
props: {
|
|
2053
|
+
columns: {},
|
|
2054
|
+
store: {}
|
|
2055
|
+
},
|
|
2056
|
+
setup(__props) {
|
|
2057
|
+
const filterableColumns = computed(() => __props.columns.filter((column) => column.filterable));
|
|
2058
|
+
const showRowActionsHeader = computed(() => __props.store.config.rowActions?.enabled ?? false);
|
|
2059
|
+
const rowActionsPosition = computed(() => __props.store.config.rowActions?.position ?? "before-index");
|
|
2060
|
+
const handleSort = (colIndex) => __props.store.sortByColumn(colIndex);
|
|
2061
|
+
const onResize = (entries) => {
|
|
2062
|
+
for (const entry of entries) {
|
|
2063
|
+
if (entry.borderBoxSize.length === 0) continue;
|
|
2064
|
+
const observedWidth = entry.borderBoxSize[0].inlineSize;
|
|
2065
|
+
const colIndex = Number(entry.target.dataset.colindex);
|
|
2066
|
+
const currentWidth = __props.store.columns[colIndex]?.width;
|
|
2067
|
+
if (typeof currentWidth === "number" && currentWidth !== observedWidth) __props.store.resizeColumn(colIndex, observedWidth);
|
|
2068
|
+
}
|
|
2069
|
+
};
|
|
2070
|
+
return (_ctx, _cache) => {
|
|
2071
|
+
return __props.columns.length ? (openBlock(), createElementBlock("thead", _hoisted_1$4, [createElementVNode("tr", _hoisted_2$3, [
|
|
2072
|
+
showRowActionsHeader.value && rowActionsPosition.value === "before-index" ? (openBlock(), createElementBlock("th", {
|
|
2073
|
+
key: 0,
|
|
2074
|
+
class: normalizeClass(["row-actions-header", { "sticky-column": rowActionsPosition.value === "before-index" }])
|
|
2075
|
+
}, null, 2)) : createCommentVNode("", true),
|
|
2076
|
+
__props.store.zeroColumn ? (openBlock(), createElementBlock("th", {
|
|
2077
|
+
key: 1,
|
|
2078
|
+
id: "header-index",
|
|
2079
|
+
class: normalizeClass([[
|
|
2080
|
+
__props.store.hasPinnedColumns ? "sticky-index" : "",
|
|
2081
|
+
__props.store.isTreeView ? "tree-index" : "",
|
|
2082
|
+
__props.store.config.view === "list-expansion" ? "list-expansion-index" : ""
|
|
2083
|
+
], "list-index"])
|
|
2084
|
+
}, null, 2)) : createCommentVNode("", true),
|
|
2085
|
+
showRowActionsHeader.value && rowActionsPosition.value === "after-index" ? (openBlock(), createElementBlock("th", _hoisted_3$1)) : createCommentVNode("", true),
|
|
2086
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.columns, (column, colKey) => {
|
|
2087
|
+
return withDirectives((openBlock(), createElementBlock("th", {
|
|
2088
|
+
key: column.name,
|
|
2089
|
+
"data-colindex": colKey,
|
|
2090
|
+
tabindex: "-1",
|
|
2091
|
+
style: normalizeStyle(__props.store.getHeaderCellStyle(column)),
|
|
2092
|
+
class: normalizeClass(`${column.pinned ? "sticky-column" : ""} ${column.sortable === false ? "" : "cursor-pointer"}`),
|
|
2093
|
+
onClick: ($event) => column.sortable !== false ? handleSort(colKey) : void 0
|
|
2094
|
+
}, [renderSlot(_ctx.$slots, "default", {}, () => [createTextVNode(toDisplayString(column.label || String.fromCharCode(colKey + 97).toUpperCase()), 1)])], 14, _hoisted_4$1)), [[unref(vResizeObserver), onResize]]);
|
|
2095
|
+
}), 128)),
|
|
2096
|
+
showRowActionsHeader.value && rowActionsPosition.value === "end" ? (openBlock(), createElementBlock("th", _hoisted_5$1)) : createCommentVNode("", true)
|
|
2097
|
+
]), filterableColumns.value.length > 0 ? (openBlock(), createElementBlock("tr", _hoisted_6$1, [
|
|
2098
|
+
showRowActionsHeader.value && rowActionsPosition.value === "before-index" ? (openBlock(), createElementBlock("th", {
|
|
2099
|
+
key: 0,
|
|
2100
|
+
class: normalizeClass(["row-actions-header", { "sticky-column": rowActionsPosition.value === "before-index" }])
|
|
2101
|
+
}, null, 2)) : createCommentVNode("", true),
|
|
2102
|
+
__props.store.zeroColumn ? (openBlock(), createElementBlock("th", {
|
|
2103
|
+
key: 1,
|
|
2104
|
+
class: normalizeClass([[
|
|
2105
|
+
__props.store.hasPinnedColumns ? "sticky-index" : "",
|
|
2106
|
+
__props.store.isTreeView ? "tree-index" : "",
|
|
2107
|
+
__props.store.config.view === "list-expansion" ? "list-expansion-index" : ""
|
|
2108
|
+
], "list-index"])
|
|
2109
|
+
}, null, 2)) : createCommentVNode("", true),
|
|
2110
|
+
showRowActionsHeader.value && rowActionsPosition.value === "after-index" ? (openBlock(), createElementBlock("th", _hoisted_7$1)) : createCommentVNode("", true),
|
|
2111
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.columns, (column, colKey) => {
|
|
2112
|
+
return openBlock(), createElementBlock("th", {
|
|
2113
|
+
key: `filter-${column.name}`,
|
|
2114
|
+
class: normalizeClass(`${column.pinned ? "sticky-column" : ""}`),
|
|
2115
|
+
style: normalizeStyle(__props.store.getHeaderCellStyle(column))
|
|
2116
|
+
}, [column.filterable ? (openBlock(), createBlock(ATableColumnFilter_default, {
|
|
2117
|
+
key: 0,
|
|
2118
|
+
column,
|
|
2119
|
+
"col-index": colKey,
|
|
2120
|
+
store: __props.store
|
|
2121
|
+
}, null, 8, [
|
|
2122
|
+
"column",
|
|
2123
|
+
"col-index",
|
|
2124
|
+
"store"
|
|
2125
|
+
])) : createCommentVNode("", true)], 6);
|
|
2126
|
+
}), 128)),
|
|
2127
|
+
showRowActionsHeader.value && rowActionsPosition.value === "end" ? (openBlock(), createElementBlock("th", _hoisted_8)) : createCommentVNode("", true)
|
|
2128
|
+
])) : createCommentVNode("", true)])) : createCommentVNode("", true);
|
|
2129
|
+
};
|
|
2130
|
+
}
|
|
2131
|
+
});
|
|
2132
|
+
//#endregion
|
|
2133
|
+
//#region src/components/ATableModal.vue
|
|
2134
|
+
var ATableModal_default = /* @__PURE__ */ defineComponent({
|
|
2135
|
+
__name: "ATableModal",
|
|
2136
|
+
props: { store: {} },
|
|
2137
|
+
setup(__props) {
|
|
2138
|
+
const amodalRef = useTemplateRef("amodal");
|
|
2139
|
+
const { width: modalWidth, height: modalHeight } = useElementBounding(amodalRef);
|
|
2140
|
+
const amodalStyles = computed(() => {
|
|
2141
|
+
if (!(__props.store.modal.height && __props.store.modal.width && __props.store.modal.left && __props.store.modal.bottom)) return {};
|
|
2142
|
+
const table = __props.store.modal.cell?.closest("table");
|
|
2143
|
+
if (!table) return {};
|
|
2144
|
+
const maxHeight = table.offsetHeight || 0;
|
|
2145
|
+
const maxWidth = table.offsetWidth || 0;
|
|
2146
|
+
let modalY = __props.store.modal.cell?.offsetTop || 0;
|
|
2147
|
+
const headerHeight = table.querySelector("thead")?.offsetHeight || 0;
|
|
2148
|
+
modalY += headerHeight;
|
|
2149
|
+
modalY = modalY + modalHeight.value < maxHeight ? modalY : modalY - (modalHeight.value + __props.store.modal.height);
|
|
2150
|
+
let modalX = __props.store.modal.cell?.offsetLeft || 0;
|
|
2151
|
+
modalX = modalX + modalWidth.value <= maxWidth ? modalX : modalX - (modalWidth.value - __props.store.modal.width);
|
|
2152
|
+
return {
|
|
2153
|
+
left: `${modalX}px`,
|
|
2154
|
+
top: `${modalY}px`
|
|
2155
|
+
};
|
|
2156
|
+
});
|
|
2157
|
+
return (_ctx, _cache) => {
|
|
2158
|
+
return openBlock(), createElementBlock("div", {
|
|
2159
|
+
ref: "amodal",
|
|
2160
|
+
class: "amodal",
|
|
2161
|
+
tabindex: "-1",
|
|
2162
|
+
style: normalizeStyle(amodalStyles.value),
|
|
2163
|
+
onClick: _cache[0] || (_cache[0] = withModifiers(() => {}, ["stop"])),
|
|
2164
|
+
onInput: _cache[1] || (_cache[1] = withModifiers(() => {}, ["stop"]))
|
|
2165
|
+
}, [renderSlot(_ctx.$slots, "default")], 36);
|
|
2166
|
+
};
|
|
2167
|
+
}
|
|
2168
|
+
});
|
|
2169
|
+
//#endregion
|
|
2170
|
+
//#region src/components/ATablePaginationFooter.vue?vue&type=script&setup=true&lang.ts
|
|
2171
|
+
var _hoisted_1$3 = {
|
|
2172
|
+
key: 0,
|
|
2173
|
+
class: "atable-pagination"
|
|
2174
|
+
};
|
|
2175
|
+
var _hoisted_2$2 = ["colspan"];
|
|
2176
|
+
var _hoisted_3 = {
|
|
2177
|
+
key: 0,
|
|
2178
|
+
class: "truncation-note"
|
|
2179
|
+
};
|
|
2180
|
+
var _hoisted_4 = {
|
|
2181
|
+
key: 1,
|
|
2182
|
+
class: "completion-note"
|
|
2183
|
+
};
|
|
2184
|
+
var _hoisted_5 = {
|
|
2185
|
+
key: 2,
|
|
2186
|
+
class: "atable-pagination-controls"
|
|
2187
|
+
};
|
|
2188
|
+
var _hoisted_6 = ["disabled"];
|
|
2189
|
+
var _hoisted_7 = ["disabled"];
|
|
2190
|
+
//#endregion
|
|
2191
|
+
//#region src/components/ATablePaginationFooter.vue
|
|
2192
|
+
var ATablePaginationFooter_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
2193
|
+
__name: "ATablePaginationFooter",
|
|
2194
|
+
props: {
|
|
2195
|
+
columnCount: {},
|
|
2196
|
+
showFooter: { type: Boolean },
|
|
2197
|
+
hasMore: { type: Boolean },
|
|
2198
|
+
hasPrev: { type: Boolean },
|
|
2199
|
+
hasNext: { type: Boolean },
|
|
2200
|
+
hasLocalNext: { type: Boolean },
|
|
2201
|
+
hasEverHadMore: { type: Boolean },
|
|
2202
|
+
loadedCount: {},
|
|
2203
|
+
loading: { type: Boolean },
|
|
2204
|
+
next: { type: Function },
|
|
2205
|
+
prev: { type: Function }
|
|
2206
|
+
},
|
|
2207
|
+
setup(__props) {
|
|
2208
|
+
const props = __props;
|
|
2209
|
+
const showCompleteNote = computed(() => !props.hasMore && props.hasEverHadMore);
|
|
2210
|
+
const showControls = computed(() => props.hasMore || props.hasPrev);
|
|
2211
|
+
const onNext = () => {
|
|
2212
|
+
props.next();
|
|
2213
|
+
};
|
|
2214
|
+
return (_ctx, _cache) => {
|
|
2215
|
+
return __props.showFooter ? (openBlock(), createElementBlock("tfoot", _hoisted_1$3, [createElementVNode("tr", null, [createElementVNode("td", { colspan: __props.columnCount }, [__props.hasMore ? (openBlock(), createElementBlock("p", _hoisted_3, "This is a partial list — more records exist on the server.")) : showCompleteNote.value ? (openBlock(), createElementBlock("p", _hoisted_4, "All " + toDisplayString(__props.loadedCount) + " records loaded.", 1)) : createCommentVNode("", true), showControls.value ? (openBlock(), createElementBlock("div", _hoisted_5, [createElementVNode("button", {
|
|
2216
|
+
type: "button",
|
|
2217
|
+
class: "atable-pagination-btn",
|
|
2218
|
+
disabled: !__props.hasPrev || __props.loading,
|
|
2219
|
+
onClick: _cache[0] || (_cache[0] = (...args) => __props.prev && __props.prev(...args))
|
|
2220
|
+
}, " Previous ", 8, _hoisted_6), createElementVNode("button", {
|
|
2221
|
+
type: "button",
|
|
2222
|
+
class: "atable-pagination-btn",
|
|
2223
|
+
disabled: !__props.hasNext || __props.loading,
|
|
2224
|
+
onClick: onNext
|
|
2225
|
+
}, toDisplayString(__props.hasMore && !__props.hasLocalNext ? "Load more" : "Next"), 9, _hoisted_7)])) : createCommentVNode("", true)], 8, _hoisted_2$2)])])) : createCommentVNode("", true);
|
|
2226
|
+
};
|
|
2227
|
+
}
|
|
2228
|
+
}), [["__scopeId", "data-v-e0e73858"]]);
|
|
2229
|
+
//#endregion
|
|
2230
|
+
//#region src/composables/table-pagination.ts
|
|
2231
|
+
/**
|
|
2232
|
+
* Window rows after filter/sort, and optionally walk {@link @stonecrop/schema#GetRecordsOptions} for the next page.
|
|
2233
|
+
* Pagination is not a filter — pass already-filtered rows.
|
|
2234
|
+
* @public
|
|
2235
|
+
*/
|
|
2236
|
+
function useTablePagination(options) {
|
|
2237
|
+
const heldRows = computed(() => toValue(options.rows));
|
|
2238
|
+
const pageSize = computed(() => toValue(options.pageSize));
|
|
2239
|
+
const sourceKey = computed(() => toValue(options.sourceKey));
|
|
2240
|
+
const windowIndex = ref(0);
|
|
2241
|
+
const loading = ref(false);
|
|
2242
|
+
const serverHasMore = ref(false);
|
|
2243
|
+
const hasEverHadMore = ref(false);
|
|
2244
|
+
const lastFetchOffset = ref(0);
|
|
2245
|
+
const lastPageLength = ref(0);
|
|
2246
|
+
const loadedCount = computed(() => heldRows.value.length);
|
|
2247
|
+
const effectivePageSize = computed(() => {
|
|
2248
|
+
const size = pageSize.value;
|
|
2249
|
+
if (size != null && size > 0) return size;
|
|
2250
|
+
const count = heldRows.value.length;
|
|
2251
|
+
return count > 0 ? count : 1;
|
|
2252
|
+
});
|
|
2253
|
+
const windowCount = computed(() => Math.max(1, Math.ceil(heldRows.value.length / effectivePageSize.value)));
|
|
2254
|
+
const visibleRows = computed(() => {
|
|
2255
|
+
const start = windowIndex.value * effectivePageSize.value;
|
|
2256
|
+
return heldRows.value.slice(start, start + effectivePageSize.value);
|
|
2257
|
+
});
|
|
2258
|
+
const hasLocalNext = computed(() => windowIndex.value < windowCount.value - 1);
|
|
2259
|
+
const hasPrev = computed(() => windowIndex.value > 0);
|
|
2260
|
+
const hasNext = computed(() => hasLocalNext.value || Boolean(options.getRecords) && serverHasMore.value);
|
|
2261
|
+
const hasMore = computed(() => serverHasMore.value);
|
|
2262
|
+
const showFooter = computed(() => {
|
|
2263
|
+
if (options.getRecords) return serverHasMore.value || hasPrev.value || loading.value || hasEverHadMore.value && !serverHasMore.value;
|
|
2264
|
+
const size = pageSize.value;
|
|
2265
|
+
return size != null && size > 0 && heldRows.value.length > size;
|
|
2266
|
+
});
|
|
2267
|
+
const resetWindow = () => {
|
|
2268
|
+
windowIndex.value = 0;
|
|
2269
|
+
hasEverHadMore.value = false;
|
|
2270
|
+
};
|
|
2271
|
+
const fetchFromServer = async (fetchOptions) => {
|
|
2272
|
+
if (!options.getRecords) return;
|
|
2273
|
+
loading.value = true;
|
|
2274
|
+
try {
|
|
2275
|
+
const result = await options.getRecords(fetchOptions);
|
|
2276
|
+
serverHasMore.value = result.hasMore;
|
|
2277
|
+
if (result.hasMore) hasEverHadMore.value = true;
|
|
2278
|
+
lastFetchOffset.value = fetchOptions?.offset ?? 0;
|
|
2279
|
+
lastPageLength.value = result.data.length;
|
|
2280
|
+
} finally {
|
|
2281
|
+
loading.value = false;
|
|
2282
|
+
}
|
|
2283
|
+
};
|
|
2284
|
+
watch(() => sourceKey.value, () => {
|
|
2285
|
+
resetWindow();
|
|
2286
|
+
if (options.getRecords) fetchFromServer();
|
|
2287
|
+
}, { immediate: true });
|
|
2288
|
+
watch(heldRows, () => {
|
|
2289
|
+
if (windowIndex.value >= windowCount.value) windowIndex.value = Math.max(0, windowCount.value - 1);
|
|
2290
|
+
});
|
|
2291
|
+
const next = async () => {
|
|
2292
|
+
if (hasLocalNext.value) {
|
|
2293
|
+
windowIndex.value += 1;
|
|
2294
|
+
return;
|
|
2295
|
+
}
|
|
2296
|
+
if (options.getRecords && serverHasMore.value) {
|
|
2297
|
+
await fetchFromServer({ offset: lastFetchOffset.value + lastPageLength.value });
|
|
2298
|
+
await nextTick();
|
|
2299
|
+
windowIndex.value = Math.max(0, windowCount.value - 1);
|
|
2300
|
+
}
|
|
2301
|
+
};
|
|
2302
|
+
const prev = () => {
|
|
2303
|
+
if (windowIndex.value > 0) windowIndex.value -= 1;
|
|
2304
|
+
};
|
|
2305
|
+
return {
|
|
2306
|
+
visibleRows,
|
|
2307
|
+
hasPrev,
|
|
2308
|
+
hasNext,
|
|
2309
|
+
hasMore,
|
|
2310
|
+
loading,
|
|
2311
|
+
next,
|
|
2312
|
+
prev,
|
|
2313
|
+
showFooter,
|
|
2314
|
+
hasLocalNext,
|
|
2315
|
+
loadedCount,
|
|
2316
|
+
hasEverHadMore
|
|
2317
|
+
};
|
|
1610
2318
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
2319
|
+
//#endregion
|
|
2320
|
+
//#region src/schemaToColumns.ts
|
|
2321
|
+
/**
|
|
2322
|
+
* Convert an array of doctype field descriptors into ATable column definitions.
|
|
2323
|
+
*
|
|
2324
|
+
* Fields are excluded when:
|
|
2325
|
+
* - `hidden: true` — field should not be visible in any view
|
|
2326
|
+
* - no `component` — non-scalar entry (nested table or fieldset), no column equivalent
|
|
2327
|
+
*
|
|
2328
|
+
* `fieldname` is renamed to `name`; `hidden` is stripped. All other `ColumnSchema` properties
|
|
2329
|
+
* spread through automatically.
|
|
2330
|
+
*
|
|
2331
|
+
* For link fields (those carrying `doctype`) without an explicit `cellComponent`:
|
|
2332
|
+
* - `linkDoctype` is set from the field's `doctype` property (used by ACell's async resolver).
|
|
2333
|
+
* - A synchronous `format` function is added (unless the field already has one) that handles
|
|
2334
|
+
* both bare ID strings and pre-resolved `{ id, displayText }` objects.
|
|
2335
|
+
*
|
|
2336
|
+
* For quantity fields — those whose `component` carries the `'quantity'` category — without an
|
|
2337
|
+
* explicit `format`, a synchronous `format` is added that renders the `{ qty, uom }` value (see
|
|
2338
|
+
* `QuantityValue` in `@stonecrop/aform`) as `"<qty> <uom>"`.
|
|
2339
|
+
*
|
|
2340
|
+
* For currency fields — those whose `component` carries the `'currency'` category — without an
|
|
2341
|
+
* explicit `format`, a synchronous `format` is added that renders the `{ amount, currency }` value
|
|
2342
|
+
* (see `CurrencyValue` in `@stonecrop/aform`) as `"<amount> <currency>"`.
|
|
2343
|
+
*
|
|
2344
|
+
* @public
|
|
2345
|
+
*/
|
|
2346
|
+
function schemaToColumns(schema) {
|
|
2347
|
+
return schema.filter((f) => !f.hidden && f.component).map(({ fieldname, hidden: _hidden, ...rest }) => {
|
|
2348
|
+
const col = Object.assign({ name: fieldname }, rest);
|
|
2349
|
+
if (rest.doctype && !rest.cellComponent) {
|
|
2350
|
+
col.linkDoctype = rest.doctype;
|
|
2351
|
+
if (!rest.format) col.format = (v) => {
|
|
2352
|
+
if (v === null || v === void 0) return "";
|
|
2353
|
+
if (typeof v === "object") {
|
|
2354
|
+
const display = v.displayText ?? v.id ?? "";
|
|
2355
|
+
return typeof display === "string" || typeof display === "number" ? String(display) : "";
|
|
2356
|
+
}
|
|
2357
|
+
return String(v);
|
|
2358
|
+
};
|
|
2359
|
+
}
|
|
2360
|
+
if (componentCategory(rest.component) === "quantity" && !rest.format) col.format = formatQuantity;
|
|
2361
|
+
if (componentCategory(rest.component) === "currency" && !rest.format) col.format = formatCurrency;
|
|
2362
|
+
return col;
|
|
2363
|
+
});
|
|
1623
2364
|
}
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
2365
|
+
//#endregion
|
|
2366
|
+
//#region src/components/ATable.vue?vue&type=script&setup=true&lang.ts
|
|
2367
|
+
var _hoisted_1$2 = {
|
|
2368
|
+
class: "atable-container",
|
|
2369
|
+
style: { "position": "relative" }
|
|
2370
|
+
};
|
|
2371
|
+
//#endregion
|
|
2372
|
+
//#region src/components/ATable.vue
|
|
2373
|
+
var ATable_default = /*#__PURE__*/ _plugin_vue_export_helper_default(/* @__PURE__ */ defineComponent({
|
|
2374
|
+
__name: "ATable",
|
|
2375
|
+
props: /*@__PURE__*/ mergeModels({
|
|
2376
|
+
id: { default: "" },
|
|
2377
|
+
config: { default: () => /* @__PURE__ */ new Object() },
|
|
2378
|
+
schema: { default: () => [] },
|
|
2379
|
+
linkResolver: {
|
|
2380
|
+
type: Function,
|
|
2381
|
+
default: void 0
|
|
2382
|
+
},
|
|
2383
|
+
getRecords: {
|
|
2384
|
+
type: Function,
|
|
2385
|
+
default: void 0
|
|
2386
|
+
},
|
|
2387
|
+
sourceKey: { default: () => void 0 }
|
|
2388
|
+
}, {
|
|
2389
|
+
"rows": { required: true },
|
|
2390
|
+
"rowsModifiers": {},
|
|
2391
|
+
"columns": {},
|
|
2392
|
+
"columnsModifiers": {}
|
|
2393
|
+
}),
|
|
2394
|
+
emits: /*@__PURE__*/ mergeModels([
|
|
2395
|
+
"cellUpdate",
|
|
2396
|
+
"gantt:drag",
|
|
2397
|
+
"connection:event",
|
|
2398
|
+
"columns:update",
|
|
2399
|
+
"row:add",
|
|
2400
|
+
"row:click",
|
|
2401
|
+
"row:delete",
|
|
2402
|
+
"row:duplicate",
|
|
2403
|
+
"row:insert-above",
|
|
2404
|
+
"row:insert-below",
|
|
2405
|
+
"row:move",
|
|
2406
|
+
"row:open"
|
|
2407
|
+
], ["update:rows", "update:columns"]),
|
|
2408
|
+
setup(__props, { expose: __expose, emit: __emit }) {
|
|
2409
|
+
const rows = useModel(__props, "rows");
|
|
2410
|
+
const columns = useModel(__props, "columns");
|
|
2411
|
+
const emit = __emit;
|
|
2412
|
+
const tableRef = useTemplateRef("table");
|
|
2413
|
+
const resolvedColumns = columns.value?.length ? columns.value : schemaToColumns(__props.schema ?? []);
|
|
2414
|
+
const injectedLinkResolver = inject("aformLinkResolver", null);
|
|
2415
|
+
const store = createTableStore({
|
|
2416
|
+
columns: resolvedColumns,
|
|
2417
|
+
rows: rows.value,
|
|
2418
|
+
id: __props.id,
|
|
2419
|
+
config: __props.config,
|
|
2420
|
+
linkResolver: __props.linkResolver ?? injectedLinkResolver
|
|
2421
|
+
});
|
|
2422
|
+
const pagination = useTablePagination({
|
|
2423
|
+
rows: () => store.filteredRows,
|
|
2424
|
+
pageSize: () => store.config.pageSize,
|
|
2425
|
+
getRecords: __props.getRecords,
|
|
2426
|
+
sourceKey: () => __props.sourceKey
|
|
2427
|
+
});
|
|
2428
|
+
const { visibleRows, showFooter, hasMore, hasPrev, hasNext, hasLocalNext, hasEverHadMore, loadedCount, loading: paginationLoading, next: paginationNext, prev: paginationPrev } = pagination;
|
|
2429
|
+
const footerColumnCount = computed(() => store.columns.length + (store.zeroColumn ? 1 : 0));
|
|
2430
|
+
store.$onAction(({ name, store: storeInstance, args, after }) => {
|
|
2431
|
+
if (name === "setCellData" || name === "setCellText") {
|
|
2432
|
+
const [colIndex, rowIndex, newValue] = args;
|
|
2433
|
+
const oldValue = storeInstance.getCellData(colIndex, rowIndex);
|
|
2434
|
+
after(() => {
|
|
2435
|
+
rows.value = [...store.rows];
|
|
2436
|
+
emit("cellUpdate", {
|
|
2437
|
+
colIndex,
|
|
2438
|
+
rowIndex,
|
|
2439
|
+
newValue,
|
|
2440
|
+
oldValue
|
|
2441
|
+
});
|
|
2442
|
+
});
|
|
2443
|
+
} else if (name === "updateGanttBar") {
|
|
2444
|
+
const [event] = args;
|
|
2445
|
+
let shouldEmit = false;
|
|
2446
|
+
if (event.type === "resize") shouldEmit = event.oldColspan !== event.newColspan;
|
|
2447
|
+
else if (event.type === "bar") shouldEmit = event.oldStart !== event.newStart || event.oldEnd !== event.newEnd;
|
|
2448
|
+
if (shouldEmit) after(() => {
|
|
2449
|
+
emit("gantt:drag", event);
|
|
2450
|
+
});
|
|
2451
|
+
} else if (name === "resizeColumn") after(() => {
|
|
2452
|
+
columns.value = [...store.columns];
|
|
2453
|
+
emit("columns:update", [...store.columns]);
|
|
2454
|
+
});
|
|
2455
|
+
});
|
|
2456
|
+
watch(() => rows.value, (newRows) => {
|
|
2457
|
+
if (JSON.stringify(newRows) !== JSON.stringify(store.rows)) store.rows = [...newRows];
|
|
2458
|
+
}, { deep: true });
|
|
2459
|
+
watch(columns, (newColumns) => {
|
|
2460
|
+
if (!newColumns) return;
|
|
2461
|
+
if (JSON.stringify(newColumns) !== JSON.stringify(store.columns)) {
|
|
2462
|
+
store.columns = [...newColumns];
|
|
2463
|
+
emit("columns:update", [...newColumns]);
|
|
2464
|
+
}
|
|
2465
|
+
}, { deep: true });
|
|
2466
|
+
onMounted(() => {
|
|
2467
|
+
if (columns.value?.some((column) => column.pinned)) {
|
|
2468
|
+
assignStickyCellWidths();
|
|
2469
|
+
if (store.isTreeView) useMutationObserver(tableRef, assignStickyCellWidths, {
|
|
2470
|
+
childList: true,
|
|
2471
|
+
subtree: true
|
|
2472
|
+
});
|
|
2473
|
+
}
|
|
2474
|
+
});
|
|
2475
|
+
const pinnedColumnCount = computed(() => {
|
|
2476
|
+
return store.columns.filter((column) => column.pinned).length;
|
|
2477
|
+
});
|
|
2478
|
+
const assignStickyCellWidths = () => {
|
|
2479
|
+
const table = tableRef.value;
|
|
2480
|
+
const headerRow = table?.rows[0];
|
|
2481
|
+
const firstDataRow = table?.rows[1];
|
|
2482
|
+
const headerCells = headerRow ? Array.from(headerRow.cells) : [];
|
|
2483
|
+
for (const [index, headerCell] of headerCells.entries()) {
|
|
2484
|
+
const rowCell = firstDataRow?.cells[index];
|
|
2485
|
+
if (rowCell) headerCell.style.width = `${rowCell.offsetWidth}px`;
|
|
2486
|
+
}
|
|
2487
|
+
for (const row of table?.rows || []) {
|
|
2488
|
+
let totalWidth = 0;
|
|
2489
|
+
const pinnedCells = [];
|
|
2490
|
+
for (const column of row.cells) if (column.classList.contains("sticky-column") || column.classList.contains("sticky-index")) {
|
|
2491
|
+
column.style.left = `${totalWidth}px`;
|
|
2492
|
+
totalWidth += column.offsetWidth;
|
|
2493
|
+
pinnedCells.push(column);
|
|
2494
|
+
}
|
|
2495
|
+
if (pinnedCells.length > 0) pinnedCells[pinnedCells.length - 1].classList.add("sticky-column-edge");
|
|
2496
|
+
}
|
|
2497
|
+
};
|
|
2498
|
+
window.addEventListener("keydown", (event) => {
|
|
2499
|
+
if (event.key === "Escape") {
|
|
2500
|
+
if (store.modal.visible) {
|
|
2501
|
+
store.modal.visible = false;
|
|
2502
|
+
const $parent = store.modal.parent;
|
|
2503
|
+
if ($parent) nextTick().then(() => {
|
|
2504
|
+
return $parent.focus();
|
|
2505
|
+
});
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
});
|
|
2509
|
+
const getProcessedColumnsForRow = (row) => {
|
|
2510
|
+
if (!row.gantt || pinnedColumnCount.value === 0) return store.columns;
|
|
2511
|
+
const result = [];
|
|
2512
|
+
for (let i = 0; i < pinnedColumnCount.value; i++) {
|
|
2513
|
+
const column = { ...store.columns[i] };
|
|
2514
|
+
column.originalIndex = i;
|
|
2515
|
+
result.push(column);
|
|
2516
|
+
}
|
|
2517
|
+
result.push({
|
|
2518
|
+
...store.columns[pinnedColumnCount.value],
|
|
2519
|
+
isGantt: true,
|
|
2520
|
+
colspan: row.gantt?.colspan || store.columns.length - pinnedColumnCount.value,
|
|
2521
|
+
originalIndex: pinnedColumnCount.value,
|
|
2522
|
+
width: "auto"
|
|
2523
|
+
});
|
|
2524
|
+
return result;
|
|
2525
|
+
};
|
|
2526
|
+
const handleConnectionCreate = (connection) => {
|
|
2527
|
+
emit("connection:event", {
|
|
2528
|
+
type: "create",
|
|
2529
|
+
connection
|
|
2530
|
+
});
|
|
2531
|
+
};
|
|
2532
|
+
const handleConnectionDelete = (connection) => {
|
|
2533
|
+
emit("connection:event", {
|
|
2534
|
+
type: "delete",
|
|
2535
|
+
connection
|
|
2536
|
+
});
|
|
2537
|
+
};
|
|
2538
|
+
/**
|
|
2539
|
+
* Handle row click events from ARow components.
|
|
2540
|
+
*/
|
|
2541
|
+
const handleRowClick = (rowIndex, event) => {
|
|
2542
|
+
const row = store.rows[rowIndex];
|
|
2543
|
+
emit("row:click", {
|
|
2544
|
+
row,
|
|
2545
|
+
rowIndex,
|
|
2546
|
+
event
|
|
2547
|
+
});
|
|
2548
|
+
};
|
|
2549
|
+
/**
|
|
2550
|
+
* Handle row action events from ARow components.
|
|
2551
|
+
* Performs the default action and emits the appropriate event.
|
|
2552
|
+
*/
|
|
2553
|
+
const handleRowAction = (actionType, rowIndex, event) => {
|
|
2554
|
+
switch (actionType) {
|
|
2555
|
+
case "add": {
|
|
2556
|
+
const newIndex = store.addRow({}, rowIndex + 1);
|
|
2557
|
+
const newRow = store.rows[newIndex];
|
|
2558
|
+
rows.value = [...store.rows];
|
|
2559
|
+
emit("row:add", {
|
|
2560
|
+
rowIndex: newIndex,
|
|
2561
|
+
row: newRow
|
|
2562
|
+
});
|
|
2563
|
+
break;
|
|
2564
|
+
}
|
|
2565
|
+
case "delete": {
|
|
2566
|
+
const deletedRow = store.deleteRow(rowIndex);
|
|
2567
|
+
if (deletedRow) {
|
|
2568
|
+
rows.value = [...store.rows];
|
|
2569
|
+
emit("row:delete", {
|
|
2570
|
+
rowIndex,
|
|
2571
|
+
row: deletedRow
|
|
2572
|
+
});
|
|
2573
|
+
}
|
|
2574
|
+
break;
|
|
2575
|
+
}
|
|
2576
|
+
case "duplicate": {
|
|
2577
|
+
const newIndex = store.duplicateRow(rowIndex);
|
|
2578
|
+
if (newIndex >= 0) {
|
|
2579
|
+
const newRow = store.rows[newIndex];
|
|
2580
|
+
rows.value = [...store.rows];
|
|
2581
|
+
emit("row:duplicate", {
|
|
2582
|
+
sourceIndex: rowIndex,
|
|
2583
|
+
newIndex,
|
|
2584
|
+
row: newRow
|
|
2585
|
+
});
|
|
2586
|
+
}
|
|
2587
|
+
break;
|
|
2588
|
+
}
|
|
2589
|
+
case "insertAbove": {
|
|
2590
|
+
const newIndex = store.insertRowAbove(rowIndex);
|
|
2591
|
+
const newRow = store.rows[newIndex];
|
|
2592
|
+
rows.value = [...store.rows];
|
|
2593
|
+
emit("row:insert-above", {
|
|
2594
|
+
targetIndex: rowIndex,
|
|
2595
|
+
newIndex,
|
|
2596
|
+
row: newRow
|
|
2597
|
+
});
|
|
2598
|
+
break;
|
|
2599
|
+
}
|
|
2600
|
+
case "insertBelow": {
|
|
2601
|
+
const newIndex = store.insertRowBelow(rowIndex);
|
|
2602
|
+
const newRow = store.rows[newIndex];
|
|
2603
|
+
rows.value = [...store.rows];
|
|
2604
|
+
emit("row:insert-below", {
|
|
2605
|
+
targetIndex: rowIndex,
|
|
2606
|
+
newIndex,
|
|
2607
|
+
row: newRow
|
|
2608
|
+
});
|
|
2609
|
+
break;
|
|
2610
|
+
}
|
|
2611
|
+
case "move":
|
|
2612
|
+
emit("row:move", {
|
|
2613
|
+
fromIndex: rowIndex,
|
|
2614
|
+
toIndex: -1
|
|
2615
|
+
});
|
|
2616
|
+
break;
|
|
2617
|
+
case "moveUp":
|
|
2618
|
+
if (rowIndex > 0 && store.moveRow(rowIndex, rowIndex - 1)) {
|
|
2619
|
+
rows.value = [...store.rows];
|
|
2620
|
+
emit("row:move", {
|
|
2621
|
+
fromIndex: rowIndex,
|
|
2622
|
+
toIndex: rowIndex - 1
|
|
2623
|
+
});
|
|
2624
|
+
}
|
|
2625
|
+
break;
|
|
2626
|
+
case "moveDown":
|
|
2627
|
+
if (rowIndex < store.rows.length - 1 && store.moveRow(rowIndex, rowIndex + 1)) {
|
|
2628
|
+
rows.value = [...store.rows];
|
|
2629
|
+
emit("row:move", {
|
|
2630
|
+
fromIndex: rowIndex,
|
|
2631
|
+
toIndex: rowIndex + 1
|
|
2632
|
+
});
|
|
2633
|
+
}
|
|
2634
|
+
break;
|
|
2635
|
+
case "open": {
|
|
2636
|
+
const row = store.rows[rowIndex];
|
|
2637
|
+
emit("row:open", {
|
|
2638
|
+
row,
|
|
2639
|
+
rowIndex,
|
|
2640
|
+
event
|
|
2641
|
+
});
|
|
2642
|
+
break;
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
};
|
|
2646
|
+
__expose({
|
|
2647
|
+
store,
|
|
2648
|
+
pagination,
|
|
2649
|
+
createConnection: store.createConnection,
|
|
2650
|
+
deleteConnection: store.deleteConnection,
|
|
2651
|
+
getConnectionsForBar: store.getConnectionsForBar,
|
|
2652
|
+
getHandlesForBar: store.getHandlesForBar,
|
|
2653
|
+
addRow: store.addRow,
|
|
2654
|
+
deleteRow: store.deleteRow,
|
|
2655
|
+
duplicateRow: store.duplicateRow,
|
|
2656
|
+
insertRowAbove: store.insertRowAbove,
|
|
2657
|
+
insertRowBelow: store.insertRowBelow,
|
|
2658
|
+
moveRow: store.moveRow
|
|
2659
|
+
});
|
|
2660
|
+
return (_ctx, _cache) => {
|
|
2661
|
+
return openBlock(), createElementBlock("div", _hoisted_1$2, [withDirectives((openBlock(), createElementBlock("table", {
|
|
2662
|
+
ref: "table",
|
|
2663
|
+
class: "atable",
|
|
2664
|
+
style: normalizeStyle({ width: unref(store).config.fullWidth ? "100%" : "auto" })
|
|
2665
|
+
}, [
|
|
2666
|
+
renderSlot(_ctx.$slots, "header", { data: unref(store) }, () => [createVNode(ATableHeader_default, {
|
|
2667
|
+
columns: unref(store).columns,
|
|
2668
|
+
store: unref(store)
|
|
2669
|
+
}, null, 8, ["columns", "store"])], true),
|
|
2670
|
+
createElementVNode("tbody", null, [renderSlot(_ctx.$slots, "body", { data: unref(store) }, () => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(visibleRows), (row, filteredIndex) => {
|
|
2671
|
+
return openBlock(), createBlock(ARow_default, {
|
|
2672
|
+
key: `${row.originalIndex}-${filteredIndex}`,
|
|
2673
|
+
row,
|
|
2674
|
+
"row-index": row.originalIndex,
|
|
2675
|
+
store: unref(store),
|
|
2676
|
+
"onRow:action": handleRowAction,
|
|
2677
|
+
"onRow:click": handleRowClick
|
|
2678
|
+
}, {
|
|
2679
|
+
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(getProcessedColumnsForRow(row), (column, colIndex) => {
|
|
2680
|
+
return openBlock(), createElementBlock(Fragment, { key: column.name }, [column.isGantt ? (openBlock(), createBlock(resolveDynamicComponent(column.ganttComponent || "AGanttCell"), {
|
|
2681
|
+
key: 0,
|
|
2682
|
+
store: unref(store),
|
|
2683
|
+
"columns-count": unref(store).columns.length - pinnedColumnCount.value,
|
|
2684
|
+
color: row.gantt?.color,
|
|
2685
|
+
start: row.gantt?.startIndex,
|
|
2686
|
+
end: row.gantt?.endIndex,
|
|
2687
|
+
colspan: column.colspan,
|
|
2688
|
+
pinned: column.pinned,
|
|
2689
|
+
"row-index": row.originalIndex,
|
|
2690
|
+
"col-index": column.originalIndex ?? colIndex,
|
|
2691
|
+
style: normalizeStyle({
|
|
2692
|
+
textAlign: column?.align || "center",
|
|
2693
|
+
minWidth: column?.width || "40ch",
|
|
2694
|
+
width: unref(store).config.fullWidth ? "auto" : null
|
|
2695
|
+
}),
|
|
2696
|
+
"onConnection:create": handleConnectionCreate
|
|
2697
|
+
}, null, 40, [
|
|
2698
|
+
"store",
|
|
2699
|
+
"columns-count",
|
|
2700
|
+
"color",
|
|
2701
|
+
"start",
|
|
2702
|
+
"end",
|
|
2703
|
+
"colspan",
|
|
2704
|
+
"pinned",
|
|
2705
|
+
"row-index",
|
|
2706
|
+
"col-index",
|
|
2707
|
+
"style"
|
|
2708
|
+
])) : (openBlock(), createBlock(resolveDynamicComponent(column.cellComponent || "ACell"), {
|
|
2709
|
+
key: 1,
|
|
2710
|
+
store: unref(store),
|
|
2711
|
+
pinned: column.pinned,
|
|
2712
|
+
"row-index": row.originalIndex,
|
|
2713
|
+
"col-index": colIndex,
|
|
2714
|
+
style: normalizeStyle({
|
|
2715
|
+
textAlign: column?.align || "center",
|
|
2716
|
+
width: unref(store).config.fullWidth ? "auto" : null
|
|
2717
|
+
}),
|
|
2718
|
+
spellcheck: "false"
|
|
2719
|
+
}, null, 8, [
|
|
2720
|
+
"store",
|
|
2721
|
+
"pinned",
|
|
2722
|
+
"row-index",
|
|
2723
|
+
"col-index",
|
|
2724
|
+
"style"
|
|
2725
|
+
]))], 64);
|
|
2726
|
+
}), 128))]),
|
|
2727
|
+
_: 2
|
|
2728
|
+
}, 1032, [
|
|
2729
|
+
"row",
|
|
2730
|
+
"row-index",
|
|
2731
|
+
"store"
|
|
2732
|
+
]);
|
|
2733
|
+
}), 128))], true)]),
|
|
2734
|
+
renderSlot(_ctx.$slots, "footer", {
|
|
2735
|
+
data: unref(store),
|
|
2736
|
+
page: unref(pagination)
|
|
2737
|
+
}, () => [createVNode(ATablePaginationFooter_default, {
|
|
2738
|
+
"column-count": footerColumnCount.value,
|
|
2739
|
+
"show-footer": unref(showFooter),
|
|
2740
|
+
"has-more": unref(hasMore),
|
|
2741
|
+
"has-prev": unref(hasPrev),
|
|
2742
|
+
"has-next": unref(hasNext),
|
|
2743
|
+
"has-local-next": unref(hasLocalNext),
|
|
2744
|
+
"has-ever-had-more": unref(hasEverHadMore),
|
|
2745
|
+
"loaded-count": unref(loadedCount),
|
|
2746
|
+
loading: unref(paginationLoading),
|
|
2747
|
+
next: unref(paginationNext),
|
|
2748
|
+
prev: unref(paginationPrev)
|
|
2749
|
+
}, null, 8, [
|
|
2750
|
+
"column-count",
|
|
2751
|
+
"show-footer",
|
|
2752
|
+
"has-more",
|
|
2753
|
+
"has-prev",
|
|
2754
|
+
"has-next",
|
|
2755
|
+
"has-local-next",
|
|
2756
|
+
"has-ever-had-more",
|
|
2757
|
+
"loaded-count",
|
|
2758
|
+
"loading",
|
|
2759
|
+
"next",
|
|
2760
|
+
"prev"
|
|
2761
|
+
])], true),
|
|
2762
|
+
renderSlot(_ctx.$slots, "modal", { data: unref(store) }, () => [withDirectives(createVNode(ATableModal_default, { store: unref(store) }, {
|
|
2763
|
+
default: withCtx(() => [(openBlock(), createBlock(resolveDynamicComponent(unref(store).modal.component), mergeProps({
|
|
2764
|
+
key: `${unref(store).modal.rowIndex}:${unref(store).modal.colIndex}`,
|
|
2765
|
+
"col-index": unref(store).modal.colIndex,
|
|
2766
|
+
"row-index": unref(store).modal.rowIndex,
|
|
2767
|
+
store: unref(store)
|
|
2768
|
+
}, unref(store).modal.componentProps), null, 16, [
|
|
2769
|
+
"col-index",
|
|
2770
|
+
"row-index",
|
|
2771
|
+
"store"
|
|
2772
|
+
]))]),
|
|
2773
|
+
_: 1
|
|
2774
|
+
}, 8, ["store"]), [[vShow, unref(store).modal.visible]])], true)
|
|
2775
|
+
], 4)), [[unref(vOnClickOutside), unref(store).closeModal]]), unref(store).isGanttView && unref(store).isDependencyGraphEnabled ? (openBlock(), createBlock(AGanttConnection_default, {
|
|
2776
|
+
key: 0,
|
|
2777
|
+
store: unref(store),
|
|
2778
|
+
"onConnection:delete": handleConnectionDelete
|
|
2779
|
+
}, null, 8, ["store"])) : createCommentVNode("", true)]);
|
|
2780
|
+
};
|
|
2781
|
+
}
|
|
2782
|
+
}), [["__scopeId", "data-v-53c8fbad"]]);
|
|
2783
|
+
//#endregion
|
|
2784
|
+
//#region src/components/ATableLoading.vue
|
|
2785
|
+
var _sfc_main$1 = {};
|
|
2786
|
+
var _hoisted_1$1 = { class: "aloading" };
|
|
2787
|
+
var _hoisted_2$1 = { class: "aloading-header" };
|
|
2788
|
+
function _sfc_render$1(_ctx, _cache) {
|
|
2789
|
+
return openBlock(), createElementBlock("div", _hoisted_1$1, [createElementVNode("h2", _hoisted_2$1, [renderSlot(_ctx.$slots, "default", {}, void 0, true)]), _cache[0] || (_cache[0] = createElementVNode("div", { class: "aloading-bar" }, null, -1))]);
|
|
1920
2790
|
}
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
2791
|
+
var ATableLoading_default = /*#__PURE__*/ _plugin_vue_export_helper_default(_sfc_main$1, [["render", _sfc_render$1], ["__scopeId", "data-v-a930a25b"]]);
|
|
2792
|
+
//#endregion
|
|
2793
|
+
//#region src/components/ATableLoadingBar.vue
|
|
2794
|
+
var _sfc_main = {};
|
|
2795
|
+
var _hoisted_1 = { class: "aloading" };
|
|
2796
|
+
var _hoisted_2 = { class: "aloading-header" };
|
|
2797
|
+
function _sfc_render(_ctx, _cache) {
|
|
2798
|
+
return openBlock(), createElementBlock("div", _hoisted_1, [createElementVNode("h2", _hoisted_2, [renderSlot(_ctx.$slots, "default", {}, void 0, true)]), _cache[0] || (_cache[0] = createElementVNode("div", { class: "aloading-bar" }, null, -1))]);
|
|
1929
2799
|
}
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
2800
|
+
var ATableLoadingBar_default = /*#__PURE__*/ _plugin_vue_export_helper_default(_sfc_main, [["render", _sfc_render], ["__scopeId", "data-v-e1165876"]]);
|
|
2801
|
+
//#endregion
|
|
2802
|
+
//#region src/index.ts
|
|
2803
|
+
/**
|
|
2804
|
+
* Install all ATable components
|
|
2805
|
+
* @param app - Vue app instance
|
|
2806
|
+
* @public
|
|
2807
|
+
*/
|
|
2808
|
+
function install(app) {
|
|
2809
|
+
app.component("ACell", ACell_default);
|
|
2810
|
+
app.component("AGanttCell", AGanttCell_default);
|
|
2811
|
+
app.component("ARow", ARow_default);
|
|
2812
|
+
app.component("ARowActions", ARowActions_default);
|
|
2813
|
+
app.component("ATable", ATable_default);
|
|
2814
|
+
app.component("ATableHeader", ATableHeader_default);
|
|
2815
|
+
app.component("ATableLoading", ATableLoading_default);
|
|
2816
|
+
app.component("ATableLoadingBar", ATableLoadingBar_default);
|
|
2817
|
+
app.component("ATableModal", ATableModal_default);
|
|
2818
|
+
app.component("ATablePaginationFooter", ATablePaginationFooter_default);
|
|
1933
2819
|
}
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
Ae as ARowActions,
|
|
1939
|
-
Xn as ATable,
|
|
1940
|
-
st as ATableHeader,
|
|
1941
|
-
Yn as ATableLoading,
|
|
1942
|
-
_n as ATableLoadingBar,
|
|
1943
|
-
it as ATableModal,
|
|
1944
|
-
rt as ATablePaginationFooter,
|
|
1945
|
-
Pt as AddIcon,
|
|
1946
|
-
zt as DeleteIcon,
|
|
1947
|
-
Xt as DuplicateIcon,
|
|
1948
|
-
Gt as InsertAboveIcon,
|
|
1949
|
-
jt as InsertBelowIcon,
|
|
1950
|
-
Wt as MoveIcon,
|
|
1951
|
-
Ut as OpenIcon,
|
|
1952
|
-
Jt as actionIcons,
|
|
1953
|
-
Dt as createTableStore,
|
|
1954
|
-
uo as install,
|
|
1955
|
-
Vn as schemaToColumns,
|
|
1956
|
-
On as useTablePagination
|
|
1957
|
-
};
|
|
1958
|
-
//# sourceMappingURL=atable.js.map
|
|
2820
|
+
//#endregion
|
|
2821
|
+
export { ACell_default as ACell, AGanttCell_default as AGanttCell, ARow_default as ARow, ARowActions_default as ARowActions, ATable_default as ATable, ATableHeader_default as ATableHeader, ATableLoading_default as ATableLoading, ATableLoadingBar_default as ATableLoadingBar, ATableModal_default as ATableModal, ATablePaginationFooter_default as ATablePaginationFooter, AddIcon, DeleteIcon, DuplicateIcon, InsertAboveIcon, InsertBelowIcon, MoveIcon, OpenIcon, actionIcons, createTableStore, install, schemaToColumns, useTablePagination };
|
|
2822
|
+
|
|
2823
|
+
//# sourceMappingURL=atable.js.map
|