@aigne/afs-ui 1.11.0-beta.12
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/LICENSE.md +26 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
- package/dist/aup-protocol.cjs +235 -0
- package/dist/aup-protocol.d.cts +78 -0
- package/dist/aup-protocol.d.cts.map +1 -0
- package/dist/aup-protocol.d.mts +78 -0
- package/dist/aup-protocol.d.mts.map +1 -0
- package/dist/aup-protocol.mjs +235 -0
- package/dist/aup-protocol.mjs.map +1 -0
- package/dist/aup-registry.cjs +2489 -0
- package/dist/aup-registry.mjs +2487 -0
- package/dist/aup-registry.mjs.map +1 -0
- package/dist/aup-spec.cjs +1467 -0
- package/dist/aup-spec.mjs +1466 -0
- package/dist/aup-spec.mjs.map +1 -0
- package/dist/aup-types.cjs +165 -0
- package/dist/aup-types.d.cts +157 -0
- package/dist/aup-types.d.cts.map +1 -0
- package/dist/aup-types.d.mts +157 -0
- package/dist/aup-types.d.mts.map +1 -0
- package/dist/aup-types.mjs +157 -0
- package/dist/aup-types.mjs.map +1 -0
- package/dist/backend.cjs +14 -0
- package/dist/backend.d.cts +104 -0
- package/dist/backend.d.cts.map +1 -0
- package/dist/backend.d.mts +104 -0
- package/dist/backend.d.mts.map +1 -0
- package/dist/backend.mjs +13 -0
- package/dist/backend.mjs.map +1 -0
- package/dist/degradation.cjs +85 -0
- package/dist/degradation.d.cts +17 -0
- package/dist/degradation.d.cts.map +1 -0
- package/dist/degradation.d.mts +17 -0
- package/dist/degradation.d.mts.map +1 -0
- package/dist/degradation.mjs +84 -0
- package/dist/degradation.mjs.map +1 -0
- package/dist/index.cjs +36 -0
- package/dist/index.d.cts +12 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.mjs +13 -0
- package/dist/runtime.cjs +117 -0
- package/dist/runtime.d.cts +59 -0
- package/dist/runtime.d.cts.map +1 -0
- package/dist/runtime.d.mts +59 -0
- package/dist/runtime.d.mts.map +1 -0
- package/dist/runtime.mjs +118 -0
- package/dist/runtime.mjs.map +1 -0
- package/dist/session.cjs +159 -0
- package/dist/session.d.cts +80 -0
- package/dist/session.d.cts.map +1 -0
- package/dist/session.d.mts +80 -0
- package/dist/session.d.mts.map +1 -0
- package/dist/session.mjs +159 -0
- package/dist/session.mjs.map +1 -0
- package/dist/snapshot.cjs +162 -0
- package/dist/snapshot.mjs +163 -0
- package/dist/snapshot.mjs.map +1 -0
- package/dist/term-page.cjs +264 -0
- package/dist/term-page.mjs +264 -0
- package/dist/term-page.mjs.map +1 -0
- package/dist/term.cjs +295 -0
- package/dist/term.d.cts +84 -0
- package/dist/term.d.cts.map +1 -0
- package/dist/term.d.mts +84 -0
- package/dist/term.d.mts.map +1 -0
- package/dist/term.mjs +296 -0
- package/dist/term.mjs.map +1 -0
- package/dist/tty.cjs +136 -0
- package/dist/tty.d.cts +53 -0
- package/dist/tty.d.cts.map +1 -0
- package/dist/tty.d.mts +53 -0
- package/dist/tty.d.mts.map +1 -0
- package/dist/tty.mjs +135 -0
- package/dist/tty.mjs.map +1 -0
- package/dist/ui-provider.cjs +4615 -0
- package/dist/ui-provider.d.cts +307 -0
- package/dist/ui-provider.d.cts.map +1 -0
- package/dist/ui-provider.d.mts +307 -0
- package/dist/ui-provider.d.mts.map +1 -0
- package/dist/ui-provider.mjs +4616 -0
- package/dist/ui-provider.mjs.map +1 -0
- package/dist/web-page/core.cjs +1388 -0
- package/dist/web-page/core.mjs +1387 -0
- package/dist/web-page/core.mjs.map +1 -0
- package/dist/web-page/css.cjs +1699 -0
- package/dist/web-page/css.mjs +1698 -0
- package/dist/web-page/css.mjs.map +1 -0
- package/dist/web-page/icons.cjs +248 -0
- package/dist/web-page/icons.mjs +248 -0
- package/dist/web-page/icons.mjs.map +1 -0
- package/dist/web-page/overlay-themes.cjs +514 -0
- package/dist/web-page/overlay-themes.mjs +513 -0
- package/dist/web-page/overlay-themes.mjs.map +1 -0
- package/dist/web-page/renderers/action.cjs +72 -0
- package/dist/web-page/renderers/action.mjs +72 -0
- package/dist/web-page/renderers/action.mjs.map +1 -0
- package/dist/web-page/renderers/broadcast.cjs +160 -0
- package/dist/web-page/renderers/broadcast.mjs +160 -0
- package/dist/web-page/renderers/broadcast.mjs.map +1 -0
- package/dist/web-page/renderers/calendar.cjs +137 -0
- package/dist/web-page/renderers/calendar.mjs +137 -0
- package/dist/web-page/renderers/calendar.mjs.map +1 -0
- package/dist/web-page/renderers/canvas.cjs +173 -0
- package/dist/web-page/renderers/canvas.mjs +173 -0
- package/dist/web-page/renderers/canvas.mjs.map +1 -0
- package/dist/web-page/renderers/cdn-loader.cjs +25 -0
- package/dist/web-page/renderers/cdn-loader.mjs +25 -0
- package/dist/web-page/renderers/cdn-loader.mjs.map +1 -0
- package/dist/web-page/renderers/chart.cjs +101 -0
- package/dist/web-page/renderers/chart.mjs +101 -0
- package/dist/web-page/renderers/chart.mjs.map +1 -0
- package/dist/web-page/renderers/deck.cjs +390 -0
- package/dist/web-page/renderers/deck.mjs +390 -0
- package/dist/web-page/renderers/deck.mjs.map +1 -0
- package/dist/web-page/renderers/device.cjs +1015 -0
- package/dist/web-page/renderers/device.mjs +1015 -0
- package/dist/web-page/renderers/device.mjs.map +1 -0
- package/dist/web-page/renderers/editor.cjs +127 -0
- package/dist/web-page/renderers/editor.mjs +127 -0
- package/dist/web-page/renderers/editor.mjs.map +1 -0
- package/dist/web-page/renderers/finance-chart.cjs +178 -0
- package/dist/web-page/renderers/finance-chart.mjs +178 -0
- package/dist/web-page/renderers/finance-chart.mjs.map +1 -0
- package/dist/web-page/renderers/frame.cjs +274 -0
- package/dist/web-page/renderers/frame.mjs +274 -0
- package/dist/web-page/renderers/frame.mjs.map +1 -0
- package/dist/web-page/renderers/globe.cjs +119 -0
- package/dist/web-page/renderers/globe.mjs +119 -0
- package/dist/web-page/renderers/globe.mjs.map +1 -0
- package/dist/web-page/renderers/input.cjs +137 -0
- package/dist/web-page/renderers/input.mjs +137 -0
- package/dist/web-page/renderers/input.mjs.map +1 -0
- package/dist/web-page/renderers/list.cjs +1243 -0
- package/dist/web-page/renderers/list.mjs +1243 -0
- package/dist/web-page/renderers/list.mjs.map +1 -0
- package/dist/web-page/renderers/map.cjs +126 -0
- package/dist/web-page/renderers/map.mjs +126 -0
- package/dist/web-page/renderers/map.mjs.map +1 -0
- package/dist/web-page/renderers/media.cjs +106 -0
- package/dist/web-page/renderers/media.mjs +106 -0
- package/dist/web-page/renderers/media.mjs.map +1 -0
- package/dist/web-page/renderers/moonphase.cjs +105 -0
- package/dist/web-page/renderers/moonphase.mjs +105 -0
- package/dist/web-page/renderers/moonphase.mjs.map +1 -0
- package/dist/web-page/renderers/natal-chart.cjs +222 -0
- package/dist/web-page/renderers/natal-chart.mjs +222 -0
- package/dist/web-page/renderers/natal-chart.mjs.map +1 -0
- package/dist/web-page/renderers/overlay.cjs +531 -0
- package/dist/web-page/renderers/overlay.mjs +531 -0
- package/dist/web-page/renderers/overlay.mjs.map +1 -0
- package/dist/web-page/renderers/table.cjs +74 -0
- package/dist/web-page/renderers/table.mjs +74 -0
- package/dist/web-page/renderers/table.mjs.map +1 -0
- package/dist/web-page/renderers/terminal.cjs +30 -0
- package/dist/web-page/renderers/terminal.mjs +30 -0
- package/dist/web-page/renderers/terminal.mjs.map +1 -0
- package/dist/web-page/renderers/text.cjs +109 -0
- package/dist/web-page/renderers/text.mjs +109 -0
- package/dist/web-page/renderers/text.mjs.map +1 -0
- package/dist/web-page/renderers/ticker.cjs +133 -0
- package/dist/web-page/renderers/ticker.mjs +133 -0
- package/dist/web-page/renderers/ticker.mjs.map +1 -0
- package/dist/web-page/renderers/time.cjs +69 -0
- package/dist/web-page/renderers/time.mjs +69 -0
- package/dist/web-page/renderers/time.mjs.map +1 -0
- package/dist/web-page/renderers/unknown.cjs +20 -0
- package/dist/web-page/renderers/unknown.mjs +20 -0
- package/dist/web-page/renderers/unknown.mjs.map +1 -0
- package/dist/web-page/renderers/view.cjs +161 -0
- package/dist/web-page/renderers/view.mjs +161 -0
- package/dist/web-page/renderers/view.mjs.map +1 -0
- package/dist/web-page/renderers/wm.cjs +669 -0
- package/dist/web-page/renderers/wm.mjs +669 -0
- package/dist/web-page/renderers/wm.mjs.map +1 -0
- package/dist/web-page/skeleton.cjs +103 -0
- package/dist/web-page/skeleton.mjs +103 -0
- package/dist/web-page/skeleton.mjs.map +1 -0
- package/dist/web-page.cjs +114 -0
- package/dist/web-page.d.cts +19 -0
- package/dist/web-page.d.cts.map +1 -0
- package/dist/web-page.d.mts +19 -0
- package/dist/web-page.d.mts.map +1 -0
- package/dist/web-page.mjs +115 -0
- package/dist/web-page.mjs.map +1 -0
- package/dist/web.cjs +827 -0
- package/dist/web.d.cts +144 -0
- package/dist/web.d.cts.map +1 -0
- package/dist/web.d.mts +144 -0
- package/dist/web.d.mts.map +1 -0
- package/dist/web.mjs +828 -0
- package/dist/web.mjs.map +1 -0
- package/dist/wm-state.cjs +172 -0
- package/dist/wm-state.mjs +171 -0
- package/dist/wm-state.mjs.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,1243 @@
|
|
|
1
|
+
//#region src/web-page/renderers/list.ts
|
|
2
|
+
const LIST_JS = `
|
|
3
|
+
// ── AFS List Primitive ──
|
|
4
|
+
// Universal data view bound to AFS paths.
|
|
5
|
+
// Two orthogonal dimensions: layout (how items arrange) × itemStyle (how each renders).
|
|
6
|
+
// Pipeline: fetch → filter → sort → transform → render.
|
|
7
|
+
|
|
8
|
+
// ── Kind Rendering Strategies ──
|
|
9
|
+
var _listKindStrategies = {
|
|
10
|
+
"fs:directory": function(entry) {
|
|
11
|
+
var name = (entry.path || entry.id || "").split("/").filter(Boolean).pop() || entry.id || "";
|
|
12
|
+
return {
|
|
13
|
+
icon: "folder",
|
|
14
|
+
label: name,
|
|
15
|
+
badge: entry.meta && entry.meta.childrenCount >= 0 ? String(entry.meta.childrenCount) : null,
|
|
16
|
+
description: null,
|
|
17
|
+
image: null,
|
|
18
|
+
cssClass: "aup-list-dir"
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
"fs:file": function(entry) {
|
|
22
|
+
var name = (entry.path || entry.id || "").split("/").filter(Boolean).pop() || entry.id || "";
|
|
23
|
+
var ext = name.split(".").pop() || "";
|
|
24
|
+
var iconMap = { ts: "code", js: "code", tsx: "code", jsx: "code", md: "scroll", json: "code", yaml: "code", yml: "code", png: "image", jpg: "image", svg: "image", css: "code", html: "code" };
|
|
25
|
+
return {
|
|
26
|
+
icon: iconMap[ext] || "edit",
|
|
27
|
+
label: name,
|
|
28
|
+
badge: entry.meta && entry.meta.size ? _listFormatSize(entry.meta.size) : null,
|
|
29
|
+
description: entry.meta && entry.meta.mimeType ? entry.meta.mimeType : null,
|
|
30
|
+
image: null,
|
|
31
|
+
cssClass: "aup-list-file"
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
"ts:task-group": function(entry) {
|
|
35
|
+
var count = entry.meta && entry.meta.childrenCount;
|
|
36
|
+
return {
|
|
37
|
+
icon: "grid",
|
|
38
|
+
label: entry.id,
|
|
39
|
+
badge: count != null && count >= 0 ? String(count) : null,
|
|
40
|
+
description: null,
|
|
41
|
+
image: null,
|
|
42
|
+
cssClass: "aup-list-group aup-list-group--" + (entry.id || "").replace(/[^a-z0-9]/gi, "-")
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
"ts:task": function(entry) {
|
|
46
|
+
var c = entry.content || {};
|
|
47
|
+
var status = c.status || "";
|
|
48
|
+
var parts = [];
|
|
49
|
+
if (c.phase) parts.push(c.phase);
|
|
50
|
+
if (c.assignee && c.assignee !== "null") parts.push(c.assignee);
|
|
51
|
+
return {
|
|
52
|
+
icon: status === "done" ? "check" : status === "in_progress" ? "play" : status === "review" ? "search" : status === "blocked" ? "x" : "clock",
|
|
53
|
+
label: entry.id,
|
|
54
|
+
badge: status || null,
|
|
55
|
+
description: parts.length > 0 ? parts.join(" \\u00b7 ") : null,
|
|
56
|
+
image: null,
|
|
57
|
+
cssClass: "aup-list-task aup-list-task--" + (status || "unknown")
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
"ts:queue-item": function(entry) {
|
|
61
|
+
var c = entry.content || {};
|
|
62
|
+
return {
|
|
63
|
+
icon: "clock",
|
|
64
|
+
label: c.taskPath || entry.id,
|
|
65
|
+
badge: c.role || null,
|
|
66
|
+
description: c.addedAt ? "Added " + c.addedAt : null,
|
|
67
|
+
image: null,
|
|
68
|
+
cssClass: "aup-list-queue"
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
"ts:intent-group": function(entry) {
|
|
72
|
+
var count = entry.meta && entry.meta.childrenCount;
|
|
73
|
+
return {
|
|
74
|
+
icon: "layers",
|
|
75
|
+
label: entry.id,
|
|
76
|
+
badge: count != null && count >= 0 ? String(count) : null,
|
|
77
|
+
description: null,
|
|
78
|
+
image: null,
|
|
79
|
+
cssClass: "aup-list-group"
|
|
80
|
+
};
|
|
81
|
+
},
|
|
82
|
+
"ts:daemon": function(entry) {
|
|
83
|
+
var c = entry.content || {};
|
|
84
|
+
return {
|
|
85
|
+
icon: "cpu",
|
|
86
|
+
label: "Daemon",
|
|
87
|
+
badge: c.version || null,
|
|
88
|
+
description: c.pid ? "PID " + c.pid + " \\u00b7 port " + c.port : null,
|
|
89
|
+
image: null,
|
|
90
|
+
cssClass: "aup-list-daemon"
|
|
91
|
+
};
|
|
92
|
+
},
|
|
93
|
+
"_default": function(entry) {
|
|
94
|
+
var isDir = _listIsDirectory(entry);
|
|
95
|
+
var desc = entry.meta && entry.meta.description;
|
|
96
|
+
var name = (entry.path || entry.id || "").split("/").filter(Boolean).pop() || entry.id || "";
|
|
97
|
+
return {
|
|
98
|
+
icon: isDir ? "folder" : "edit",
|
|
99
|
+
label: name,
|
|
100
|
+
badge: isDir && entry.meta.childrenCount >= 0 ? String(entry.meta.childrenCount) : null,
|
|
101
|
+
description: desc ? String(desc).slice(0, 100) : null,
|
|
102
|
+
image: null,
|
|
103
|
+
cssClass: isDir ? "aup-list-dir" : "aup-list-item"
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
function _listResolveStrategy(entry) {
|
|
109
|
+
var kind = (entry.meta && entry.meta.kind) || "";
|
|
110
|
+
if (_listKindStrategies[kind]) return _listKindStrategies[kind](entry);
|
|
111
|
+
var parts = kind.split(":");
|
|
112
|
+
if (parts.length > 1) {
|
|
113
|
+
var withSeg = parts[0] + ":" + kind.split(":")[1].split("-")[0];
|
|
114
|
+
if (_listKindStrategies[withSeg]) return _listKindStrategies[withSeg](entry);
|
|
115
|
+
}
|
|
116
|
+
return _listKindStrategies._default(entry);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function _listResolveField(obj, dotPath) {
|
|
120
|
+
if (!dotPath) return null;
|
|
121
|
+
var parts = dotPath.split(".");
|
|
122
|
+
var val = obj;
|
|
123
|
+
for (var i = 0; i < parts.length; i++) {
|
|
124
|
+
if (val == null) return null;
|
|
125
|
+
val = val[parts[i]];
|
|
126
|
+
}
|
|
127
|
+
return val != null ? String(val) : null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function _listIsDirectory(entry) {
|
|
131
|
+
if (!entry.meta) return false;
|
|
132
|
+
var cc = entry.meta.childrenCount;
|
|
133
|
+
return cc != null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function _listFormatSize(bytes) {
|
|
137
|
+
if (bytes == null) return "";
|
|
138
|
+
if (bytes < 1024) return bytes + " B";
|
|
139
|
+
if (bytes < 1048576) return (bytes / 1024).toFixed(1) + " KB";
|
|
140
|
+
return (bytes / 1048576).toFixed(1) + " MB";
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function _listMakeIcon(name) {
|
|
144
|
+
if (!name || !_ICON_PATHS[name]) return null;
|
|
145
|
+
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
146
|
+
svg.setAttribute("viewBox", "0 0 24 24");
|
|
147
|
+
svg.setAttribute("fill", "none");
|
|
148
|
+
svg.setAttribute("stroke", "currentColor");
|
|
149
|
+
svg.setAttribute("stroke-width", "2");
|
|
150
|
+
svg.setAttribute("stroke-linecap", "round");
|
|
151
|
+
svg.setAttribute("stroke-linejoin", "round");
|
|
152
|
+
svg.classList.add("aup-icon-svg");
|
|
153
|
+
svg.innerHTML = _ICON_PATHS[name];
|
|
154
|
+
return svg;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// ── Filter/Sort/Transform helpers ──
|
|
158
|
+
function _listApplyFilter(entries, filter) {
|
|
159
|
+
if (!filter) return entries;
|
|
160
|
+
if (typeof filter === "string") {
|
|
161
|
+
var q = filter.toLowerCase();
|
|
162
|
+
return entries.filter(function(e) {
|
|
163
|
+
return (e.id || "").toLowerCase().indexOf(q) >= 0;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
if (filter.kind) {
|
|
167
|
+
var kindFilter = filter.kind;
|
|
168
|
+
return entries.filter(function(e) {
|
|
169
|
+
var k = (e.meta && e.meta.kind) || "";
|
|
170
|
+
return k === kindFilter || k.indexOf(kindFilter) === 0;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (filter.field && filter.match != null) {
|
|
174
|
+
return entries.filter(function(e) {
|
|
175
|
+
var val = _listResolveField(e, filter.field);
|
|
176
|
+
if (typeof filter.match === "string") return val === filter.match;
|
|
177
|
+
return val != null;
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (filter.exclude) {
|
|
181
|
+
var excl = Array.isArray(filter.exclude) ? filter.exclude : [filter.exclude];
|
|
182
|
+
return entries.filter(function(e) {
|
|
183
|
+
return excl.indexOf(e.id) < 0;
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
return entries;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function _listApplySort(entries, sort) {
|
|
190
|
+
if (!sort) return entries;
|
|
191
|
+
var field = typeof sort === "string" ? sort : sort.field || "id";
|
|
192
|
+
var desc = sort.desc === true;
|
|
193
|
+
return entries.slice().sort(function(a, b) {
|
|
194
|
+
var va = _listResolveField(a, field) || "";
|
|
195
|
+
var vb = _listResolveField(b, field) || "";
|
|
196
|
+
var cmp = va < vb ? -1 : va > vb ? 1 : 0;
|
|
197
|
+
return desc ? -cmp : cmp;
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function _listApplyTransform(entries, transform) {
|
|
202
|
+
if (!transform) return entries;
|
|
203
|
+
return entries.map(function(e) {
|
|
204
|
+
var t = Object.assign({}, e);
|
|
205
|
+
if (!t._transform) t._transform = {};
|
|
206
|
+
if (transform.label) t._transform.label = _listResolveField(e, transform.label);
|
|
207
|
+
if (transform.description) t._transform.description = _listResolveField(e, transform.description);
|
|
208
|
+
if (transform.badge) t._transform.badge = _listResolveField(e, transform.badge);
|
|
209
|
+
if (transform.icon) t._transform.icon = transform.icon;
|
|
210
|
+
if (transform.image) t._transform.image = _listResolveField(e, transform.image);
|
|
211
|
+
return t;
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function renderAupList(node) {
|
|
216
|
+
var el = document.createElement("div");
|
|
217
|
+
el.className = "aup-list";
|
|
218
|
+
var p = node.props || {};
|
|
219
|
+
|
|
220
|
+
// ── Two orthogonal dimensions ──
|
|
221
|
+
// layout: how items are arranged in space
|
|
222
|
+
// itemStyle: how each individual item renders
|
|
223
|
+
var layout = p.layout || p.variant || "list";
|
|
224
|
+
// Backward compat: variant "flat" → layout "list", "grouped" → "list" with grouped behavior
|
|
225
|
+
if (layout === "flat") layout = "list";
|
|
226
|
+
var isGrouped = layout === "grouped" || (p.variant === "grouped");
|
|
227
|
+
if (isGrouped) layout = "list";
|
|
228
|
+
|
|
229
|
+
var itemStyle = p.itemStyle || "row";
|
|
230
|
+
var clickMode = p.clickMode || "select";
|
|
231
|
+
var labelField = p.labelField || "id";
|
|
232
|
+
var descField = p.descriptionField != null ? p.descriptionField : "meta.description";
|
|
233
|
+
var emptyText = p.emptyText || "No items";
|
|
234
|
+
var showBreadcrumb = p.showBreadcrumb !== false;
|
|
235
|
+
var kindIconOverrides = p.kindIcons || {};
|
|
236
|
+
var maxDepth = typeof p.maxDepth === "number" ? p.maxDepth : 3;
|
|
237
|
+
var fields = p.fields || null;
|
|
238
|
+
var filter = p.filter || null;
|
|
239
|
+
var sort = p.sort || null;
|
|
240
|
+
var transform = p.transform || null;
|
|
241
|
+
var columns = p.columns || null;
|
|
242
|
+
var gridCols = p.gridCols || null;
|
|
243
|
+
var minItemWidth = p.minItemWidth || null;
|
|
244
|
+
var imageFit = p.imageFit || "cover"; // cover (aspect-fill) | contain (aspect-fit) | fill
|
|
245
|
+
var imageHeight = p.imageHeight || null; // e.g. "200px", "50%", number (px)
|
|
246
|
+
var imageShape = p.imageShape || "rect"; // rect (default) | circle (avatar-friendly)
|
|
247
|
+
var pageSize = typeof p.pageSize === "number" && p.pageSize > 0 ? p.pageSize : 0;
|
|
248
|
+
var _virtual = !!p.virtual;
|
|
249
|
+
var _estimatedHeight = typeof p.estimatedItemHeight === "number" ? p.estimatedItemHeight : 48;
|
|
250
|
+
var _bufferItems = typeof p.bufferItems === "number" ? p.bufferItems : 5;
|
|
251
|
+
|
|
252
|
+
el.setAttribute("data-layout", layout);
|
|
253
|
+
el.setAttribute("data-item-style", itemStyle);
|
|
254
|
+
if (isGrouped) el.setAttribute("data-grouped", "true");
|
|
255
|
+
|
|
256
|
+
// Self-sizing grid: set CSS variables for grid-template-columns
|
|
257
|
+
if (layout === "grid" || layout === "masonry") {
|
|
258
|
+
if (gridCols) {
|
|
259
|
+
el.style.setProperty("--list-cols", String(gridCols));
|
|
260
|
+
} else if (minItemWidth) {
|
|
261
|
+
el.style.setProperty("--list-min-width", minItemWidth);
|
|
262
|
+
el.setAttribute("data-auto-fill", "true");
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// ── Internal State ──
|
|
267
|
+
var _currentPath = node.src || "";
|
|
268
|
+
var _pathStack = [_currentPath];
|
|
269
|
+
var _entries = [];
|
|
270
|
+
var _expanded = {};
|
|
271
|
+
var _childCache = {};
|
|
272
|
+
var _selectedId = (node.state && node.state.selected) || null;
|
|
273
|
+
var _unsubscribe = null;
|
|
274
|
+
var _total = 0;
|
|
275
|
+
var _loadedCount = 0;
|
|
276
|
+
var _loadingMore = false;
|
|
277
|
+
var _filterQuery = "";
|
|
278
|
+
var _slideIndex = 0;
|
|
279
|
+
var _itemHeights = [];
|
|
280
|
+
var _virtualRenderedRange = null;
|
|
281
|
+
var _srcRoot = node.src || "";
|
|
282
|
+
|
|
283
|
+
// Build the full AFS path for an entry.
|
|
284
|
+
// Prefer entry.path (full mount-aware path from AFS core) when available.
|
|
285
|
+
// Fall back to constructing from entry.id + parent for legacy providers.
|
|
286
|
+
function _buildEntryPath(entry, parentPath) {
|
|
287
|
+
if (entry.path) return entry.path;
|
|
288
|
+
var eid = entry.id || "";
|
|
289
|
+
if (eid.charAt(0) === "/") {
|
|
290
|
+
// Absolute provider path — join with src root
|
|
291
|
+
return _srcRoot + eid;
|
|
292
|
+
}
|
|
293
|
+
// Relative id — join with parent
|
|
294
|
+
return parentPath + (parentPath.endsWith("/") ? "" : "/") + eid;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// ── Template Detection ──
|
|
298
|
+
var _itemTemplate = null;
|
|
299
|
+
var _headerTemplate = null;
|
|
300
|
+
var _emptyTemplate = null;
|
|
301
|
+
if (node.children && node.children.length) {
|
|
302
|
+
for (var ci = 0; ci < node.children.length; ci++) {
|
|
303
|
+
var ch = node.children[ci];
|
|
304
|
+
var chRole = ch.props && ch.props.role;
|
|
305
|
+
if (chRole === "item") _itemTemplate = ch;
|
|
306
|
+
else if (chRole === "header") _headerTemplate = ch;
|
|
307
|
+
else if (chRole === "empty") _emptyTemplate = ch;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// ── Template Binding ──
|
|
312
|
+
function _bindFieldPath(entry, dotPath) {
|
|
313
|
+
var parts = dotPath.split(".");
|
|
314
|
+
var val = entry;
|
|
315
|
+
for (var bi = 0; bi < parts.length; bi++) {
|
|
316
|
+
if (val == null) return null;
|
|
317
|
+
// Auto-parse JSON strings when more path parts remain
|
|
318
|
+
if (typeof val === "string" && bi < parts.length) {
|
|
319
|
+
try { val = JSON.parse(val); } catch(_) { return null; }
|
|
320
|
+
}
|
|
321
|
+
val = val[parts[bi]];
|
|
322
|
+
}
|
|
323
|
+
return val != null ? String(val) : null;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function _bindStringsDeep(obj, entry) {
|
|
327
|
+
for (var bk in obj) {
|
|
328
|
+
var bv = obj[bk];
|
|
329
|
+
if (typeof bv === "string") {
|
|
330
|
+
obj[bk] = bv.replace(/\\$\\{entry\\.([^}]+)\\}/g, function(_, fp) {
|
|
331
|
+
return _bindFieldPath(entry, fp) || "";
|
|
332
|
+
});
|
|
333
|
+
} else if (Array.isArray(bv)) {
|
|
334
|
+
for (var ai = 0; ai < bv.length; ai++) {
|
|
335
|
+
if (bv[ai] && typeof bv[ai] === "object") {
|
|
336
|
+
_bindStringsDeep(bv[ai], entry);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
} else if (bv && typeof bv === "object") {
|
|
340
|
+
_bindStringsDeep(bv, entry);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function _bindTemplate(tplNode, entry) {
|
|
346
|
+
var bound = JSON.parse(JSON.stringify(tplNode));
|
|
347
|
+
_bindStringsDeep(bound, entry);
|
|
348
|
+
bound.id = tplNode.id + "--" + entry.id;
|
|
349
|
+
return bound;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// ── DOM Structure ──
|
|
353
|
+
|
|
354
|
+
// Search bar
|
|
355
|
+
var searchEl = null;
|
|
356
|
+
if (p.searchable) {
|
|
357
|
+
searchEl = document.createElement("div");
|
|
358
|
+
searchEl.className = "aup-list-search";
|
|
359
|
+
var searchInput = document.createElement("input");
|
|
360
|
+
searchInput.type = "text";
|
|
361
|
+
searchInput.placeholder = p.searchPlaceholder || "Search...";
|
|
362
|
+
searchInput.className = "aup-list-search-input";
|
|
363
|
+
searchInput.oninput = function() {
|
|
364
|
+
_filterQuery = searchInput.value;
|
|
365
|
+
renderEntries();
|
|
366
|
+
};
|
|
367
|
+
searchEl.appendChild(searchInput);
|
|
368
|
+
el.appendChild(searchEl);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Breadcrumb
|
|
372
|
+
var breadcrumbEl = null;
|
|
373
|
+
if (showBreadcrumb && (clickMode === "navigate" || clickMode === "both")) {
|
|
374
|
+
breadcrumbEl = document.createElement("div");
|
|
375
|
+
breadcrumbEl.className = "aup-list-breadcrumb";
|
|
376
|
+
el.appendChild(breadcrumbEl);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
var loadingEl = document.createElement("div");
|
|
380
|
+
loadingEl.className = "aup-list-loading";
|
|
381
|
+
loadingEl.textContent = "Loading...";
|
|
382
|
+
el.appendChild(loadingEl);
|
|
383
|
+
|
|
384
|
+
var bodyEl = document.createElement("div");
|
|
385
|
+
bodyEl.className = "aup-list-body";
|
|
386
|
+
if (gridCols) bodyEl.style.setProperty("--list-cols", String(gridCols));
|
|
387
|
+
el.appendChild(bodyEl);
|
|
388
|
+
|
|
389
|
+
// Slideshow controls
|
|
390
|
+
var slideshowNav = null;
|
|
391
|
+
if (layout === "slideshow") {
|
|
392
|
+
slideshowNav = document.createElement("div");
|
|
393
|
+
slideshowNav.className = "aup-list-slideshow-nav";
|
|
394
|
+
var prevBtn = document.createElement("button");
|
|
395
|
+
prevBtn.className = "aup-list-slide-btn";
|
|
396
|
+
prevBtn.textContent = "\\u25C0";
|
|
397
|
+
prevBtn.onclick = function() { slideTo(_slideIndex - 1); };
|
|
398
|
+
var nextBtn = document.createElement("button");
|
|
399
|
+
nextBtn.className = "aup-list-slide-btn";
|
|
400
|
+
nextBtn.textContent = "\\u25B6";
|
|
401
|
+
nextBtn.onclick = function() { slideTo(_slideIndex + 1); };
|
|
402
|
+
var slideCounter = document.createElement("span");
|
|
403
|
+
slideCounter.className = "aup-list-slide-counter";
|
|
404
|
+
slideshowNav.appendChild(prevBtn);
|
|
405
|
+
slideshowNav.appendChild(slideCounter);
|
|
406
|
+
slideshowNav.appendChild(nextBtn);
|
|
407
|
+
el.appendChild(slideshowNav);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// ── Fields → Transform mapping ──
|
|
411
|
+
// Semantic slot names → internal _transform keys
|
|
412
|
+
// Agent writes: fields: { title: "content.name", image: "content.src" }
|
|
413
|
+
// Internally: _transform.label = resolve("content.name"), _transform.image = resolve("content.src")
|
|
414
|
+
var _fieldsSlotMap = {
|
|
415
|
+
title: "label",
|
|
416
|
+
subtitle: "description",
|
|
417
|
+
image: "image",
|
|
418
|
+
badge: "badge",
|
|
419
|
+
icon: "icon",
|
|
420
|
+
alt: "alt",
|
|
421
|
+
footer: "footer"
|
|
422
|
+
};
|
|
423
|
+
|
|
424
|
+
function _listApplyFields(entries, fieldsSpec) {
|
|
425
|
+
if (!fieldsSpec) return entries;
|
|
426
|
+
return entries.map(function(e) {
|
|
427
|
+
var t = Object.assign({}, e);
|
|
428
|
+
if (!t._transform) t._transform = {};
|
|
429
|
+
for (var slot in fieldsSpec) {
|
|
430
|
+
var internalKey = _fieldsSlotMap[slot] || slot;
|
|
431
|
+
var dotPath = fieldsSpec[slot];
|
|
432
|
+
if (internalKey === "icon") {
|
|
433
|
+
// Resolve dot-path to get icon name from entry data
|
|
434
|
+
var iconVal = _bindFieldPath(e, dotPath);
|
|
435
|
+
if (iconVal != null) t._transform.icon = iconVal;
|
|
436
|
+
} else {
|
|
437
|
+
// Use _bindFieldPath which auto-parses JSON strings in content
|
|
438
|
+
var resolved = _bindFieldPath(e, dotPath);
|
|
439
|
+
if (resolved != null) t._transform[internalKey] = resolved;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return t;
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// ── Pipeline ──
|
|
447
|
+
function processPipeline(entries) {
|
|
448
|
+
var result = entries;
|
|
449
|
+
result = _listApplyFilter(result, filter);
|
|
450
|
+
if (_filterQuery) result = _listApplyFilter(result, _filterQuery);
|
|
451
|
+
result = _listApplySort(result, sort);
|
|
452
|
+
result = _listApplyTransform(result, transform);
|
|
453
|
+
// fields overrides transform (more specific, agent-friendly API)
|
|
454
|
+
result = _listApplyFields(result, fields);
|
|
455
|
+
return result;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// ── Breadcrumb ──
|
|
459
|
+
function renderBreadcrumb() {
|
|
460
|
+
if (!breadcrumbEl) return;
|
|
461
|
+
breadcrumbEl.innerHTML = "";
|
|
462
|
+
for (var i = 0; i < _pathStack.length; i++) {
|
|
463
|
+
if (i > 0) {
|
|
464
|
+
var sep = document.createElement("span");
|
|
465
|
+
sep.className = "aup-list-breadcrumb-sep";
|
|
466
|
+
sep.textContent = " / ";
|
|
467
|
+
breadcrumbEl.appendChild(sep);
|
|
468
|
+
}
|
|
469
|
+
var seg = document.createElement("span");
|
|
470
|
+
var segPath = _pathStack[i];
|
|
471
|
+
var segName = segPath.split("/").filter(Boolean).pop() || "/";
|
|
472
|
+
if (i < _pathStack.length - 1) {
|
|
473
|
+
seg.className = "aup-list-breadcrumb-seg";
|
|
474
|
+
seg.textContent = segName;
|
|
475
|
+
(function(targetPath, targetIdx) {
|
|
476
|
+
seg.onclick = function() { navigateTo(targetPath, targetIdx); };
|
|
477
|
+
})(segPath, i);
|
|
478
|
+
} else {
|
|
479
|
+
seg.className = "aup-list-breadcrumb-cur";
|
|
480
|
+
seg.textContent = segName;
|
|
481
|
+
}
|
|
482
|
+
breadcrumbEl.appendChild(seg);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// ── Item Style Renderers ──
|
|
487
|
+
// Each returns a DOM element for one entry.
|
|
488
|
+
|
|
489
|
+
function renderItemRow(entry, strategy, t) {
|
|
490
|
+
var row = document.createElement("div");
|
|
491
|
+
row.className = "aup-list-row " + (strategy.cssClass || "");
|
|
492
|
+
|
|
493
|
+
var iconName = t.icon || kindIconOverrides[(entry.meta && entry.meta.kind) || ""] || strategy.icon;
|
|
494
|
+
var iconWrap = document.createElement("span");
|
|
495
|
+
iconWrap.className = "aup-list-icon";
|
|
496
|
+
var svgIcon = _listMakeIcon(iconName);
|
|
497
|
+
if (svgIcon) iconWrap.appendChild(svgIcon);
|
|
498
|
+
row.appendChild(iconWrap);
|
|
499
|
+
|
|
500
|
+
var textWrap = document.createElement("div");
|
|
501
|
+
textWrap.className = "aup-list-text";
|
|
502
|
+
var labelText = t.label || strategy.label || _listResolveField(entry, labelField) || entry.id || "";
|
|
503
|
+
var label = document.createElement("div");
|
|
504
|
+
label.className = "aup-list-label";
|
|
505
|
+
label.textContent = labelText;
|
|
506
|
+
textWrap.appendChild(label);
|
|
507
|
+
var desc = t.description || (descField ? _listResolveField(entry, descField) : null) || strategy.description || null;
|
|
508
|
+
if (desc) {
|
|
509
|
+
var descEl = document.createElement("div");
|
|
510
|
+
descEl.className = "aup-list-desc";
|
|
511
|
+
descEl.textContent = desc;
|
|
512
|
+
textWrap.appendChild(descEl);
|
|
513
|
+
}
|
|
514
|
+
row.appendChild(textWrap);
|
|
515
|
+
|
|
516
|
+
var badgeText = t.badge || strategy.badge;
|
|
517
|
+
if (badgeText) {
|
|
518
|
+
var badge = document.createElement("span");
|
|
519
|
+
badge.className = "aup-list-badge";
|
|
520
|
+
badge.textContent = badgeText;
|
|
521
|
+
row.appendChild(badge);
|
|
522
|
+
}
|
|
523
|
+
return row;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function renderItemCard(entry, strategy, t) {
|
|
527
|
+
var card = document.createElement("div");
|
|
528
|
+
card.className = "aup-list-card " + (strategy.cssClass || "");
|
|
529
|
+
|
|
530
|
+
var imgSrc = t.image || strategy.image;
|
|
531
|
+
if (imgSrc) {
|
|
532
|
+
if (imageShape === "circle") {
|
|
533
|
+
var imgWrap = document.createElement("div");
|
|
534
|
+
imgWrap.className = "aup-list-card-avatar-area";
|
|
535
|
+
var imgEl = document.createElement("div");
|
|
536
|
+
imgEl.className = "aup-list-card-avatar";
|
|
537
|
+
imgEl.style.backgroundImage = "url(" + _escapeHtml(imgSrc) + ")";
|
|
538
|
+
if (t.alt) imgEl.setAttribute("role", "img");
|
|
539
|
+
if (t.alt) imgEl.setAttribute("aria-label", t.alt);
|
|
540
|
+
imgWrap.appendChild(imgEl);
|
|
541
|
+
card.appendChild(imgWrap);
|
|
542
|
+
} else {
|
|
543
|
+
var img = document.createElement("div");
|
|
544
|
+
img.className = "aup-list-card-image";
|
|
545
|
+
img.style.backgroundImage = "url(" + _escapeHtml(imgSrc) + ")";
|
|
546
|
+
img.style.backgroundSize = imageFit;
|
|
547
|
+
if (imageHeight) img.style.height = typeof imageHeight === "number" ? imageHeight + "px" : imageHeight;
|
|
548
|
+
if (t.alt) img.setAttribute("role", "img");
|
|
549
|
+
if (t.alt) img.setAttribute("aria-label", t.alt);
|
|
550
|
+
card.appendChild(img);
|
|
551
|
+
}
|
|
552
|
+
} else {
|
|
553
|
+
var iconName = t.icon || kindIconOverrides[(entry.meta && entry.meta.kind) || ""] || strategy.icon;
|
|
554
|
+
var iconArea = document.createElement("div");
|
|
555
|
+
iconArea.className = "aup-list-card-icon-area";
|
|
556
|
+
var svgIcon = _listMakeIcon(iconName);
|
|
557
|
+
if (svgIcon) iconArea.appendChild(svgIcon);
|
|
558
|
+
card.appendChild(iconArea);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
var body = document.createElement("div");
|
|
562
|
+
body.className = "aup-list-card-body";
|
|
563
|
+
var labelText = t.label || strategy.label || _listResolveField(entry, labelField) || entry.id || "";
|
|
564
|
+
var label = document.createElement("div");
|
|
565
|
+
label.className = "aup-list-card-title";
|
|
566
|
+
label.textContent = labelText;
|
|
567
|
+
body.appendChild(label);
|
|
568
|
+
var desc = t.description || (descField ? _listResolveField(entry, descField) : null) || strategy.description || null;
|
|
569
|
+
if (desc) {
|
|
570
|
+
var descEl = document.createElement("div");
|
|
571
|
+
descEl.className = "aup-list-card-desc";
|
|
572
|
+
descEl.textContent = desc;
|
|
573
|
+
body.appendChild(descEl);
|
|
574
|
+
}
|
|
575
|
+
var badgeText = t.badge || strategy.badge;
|
|
576
|
+
if (badgeText) {
|
|
577
|
+
var badge = document.createElement("span");
|
|
578
|
+
badge.className = "aup-list-badge";
|
|
579
|
+
badge.textContent = badgeText;
|
|
580
|
+
body.appendChild(badge);
|
|
581
|
+
}
|
|
582
|
+
var footerText = t.footer || null;
|
|
583
|
+
if (footerText) {
|
|
584
|
+
var footerEl = document.createElement("div");
|
|
585
|
+
footerEl.className = "aup-list-card-footer";
|
|
586
|
+
footerEl.textContent = footerText;
|
|
587
|
+
body.appendChild(footerEl);
|
|
588
|
+
}
|
|
589
|
+
card.appendChild(body);
|
|
590
|
+
return card;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
function renderItemCompact(entry, strategy, t) {
|
|
594
|
+
var row = document.createElement("div");
|
|
595
|
+
row.className = "aup-list-compact " + (strategy.cssClass || "");
|
|
596
|
+
var iconName = t.icon || kindIconOverrides[(entry.meta && entry.meta.kind) || ""] || strategy.icon;
|
|
597
|
+
var svgIcon = _listMakeIcon(iconName);
|
|
598
|
+
if (svgIcon) {
|
|
599
|
+
var iconWrap = document.createElement("span");
|
|
600
|
+
iconWrap.className = "aup-list-icon";
|
|
601
|
+
iconWrap.appendChild(svgIcon);
|
|
602
|
+
row.appendChild(iconWrap);
|
|
603
|
+
}
|
|
604
|
+
var label = document.createElement("span");
|
|
605
|
+
label.className = "aup-list-label";
|
|
606
|
+
label.textContent = t.label || strategy.label || _listResolveField(entry, labelField) || entry.id || "";
|
|
607
|
+
row.appendChild(label);
|
|
608
|
+
return row;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
function renderItemMedia(entry, strategy, t) {
|
|
612
|
+
var card = document.createElement("div");
|
|
613
|
+
card.className = "aup-list-media " + (strategy.cssClass || "");
|
|
614
|
+
|
|
615
|
+
var imgSrc = t.image || strategy.image;
|
|
616
|
+
if (imgSrc) {
|
|
617
|
+
var img = document.createElement("img");
|
|
618
|
+
img.className = "aup-list-media-img";
|
|
619
|
+
img.src = imgSrc;
|
|
620
|
+
img.alt = t.alt || entry.id || "";
|
|
621
|
+
img.loading = "lazy";
|
|
622
|
+
img.style.objectFit = imageFit;
|
|
623
|
+
card.appendChild(img);
|
|
624
|
+
} else {
|
|
625
|
+
var placeholder = document.createElement("div");
|
|
626
|
+
placeholder.className = "aup-list-media-placeholder";
|
|
627
|
+
var svgIcon = _listMakeIcon(t.icon || strategy.icon || "image");
|
|
628
|
+
if (svgIcon) placeholder.appendChild(svgIcon);
|
|
629
|
+
card.appendChild(placeholder);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
var overlay = document.createElement("div");
|
|
633
|
+
overlay.className = "aup-list-media-overlay";
|
|
634
|
+
var labelText = t.label || strategy.label || _listResolveField(entry, labelField) || entry.id || "";
|
|
635
|
+
if (labelText) {
|
|
636
|
+
var label = document.createElement("div");
|
|
637
|
+
label.className = "aup-list-media-title";
|
|
638
|
+
label.textContent = labelText;
|
|
639
|
+
overlay.appendChild(label);
|
|
640
|
+
}
|
|
641
|
+
var subtitleText = t.description || (descField ? _listResolveField(entry, descField) : null) || strategy.description || null;
|
|
642
|
+
if (subtitleText) {
|
|
643
|
+
var subtitle = document.createElement("div");
|
|
644
|
+
subtitle.className = "aup-list-media-subtitle";
|
|
645
|
+
subtitle.textContent = subtitleText;
|
|
646
|
+
overlay.appendChild(subtitle);
|
|
647
|
+
}
|
|
648
|
+
var footerText = t.footer || null;
|
|
649
|
+
if (footerText) {
|
|
650
|
+
var footer = document.createElement("div");
|
|
651
|
+
footer.className = "aup-list-media-footer";
|
|
652
|
+
footer.textContent = footerText;
|
|
653
|
+
overlay.appendChild(footer);
|
|
654
|
+
}
|
|
655
|
+
card.appendChild(overlay);
|
|
656
|
+
return card;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
function renderItemHero(entry, strategy, t) {
|
|
660
|
+
var hero = document.createElement("div");
|
|
661
|
+
hero.className = "aup-list-hero " + (strategy.cssClass || "");
|
|
662
|
+
|
|
663
|
+
var imgSrc = t.image || strategy.image;
|
|
664
|
+
if (imgSrc) {
|
|
665
|
+
hero.style.backgroundImage = "url(" + _escapeHtml(imgSrc) + ")";
|
|
666
|
+
hero.style.backgroundSize = imageFit;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
var content = document.createElement("div");
|
|
670
|
+
content.className = "aup-list-hero-content";
|
|
671
|
+
var label = document.createElement("div");
|
|
672
|
+
label.className = "aup-list-hero-title";
|
|
673
|
+
label.textContent = t.label || strategy.label || _listResolveField(entry, labelField) || entry.id || "";
|
|
674
|
+
content.appendChild(label);
|
|
675
|
+
var desc = t.description || (descField ? _listResolveField(entry, descField) : null) || strategy.description || null;
|
|
676
|
+
if (desc) {
|
|
677
|
+
var descEl = document.createElement("div");
|
|
678
|
+
descEl.className = "aup-list-hero-desc";
|
|
679
|
+
descEl.textContent = desc;
|
|
680
|
+
content.appendChild(descEl);
|
|
681
|
+
}
|
|
682
|
+
var footerText = t.footer || null;
|
|
683
|
+
if (footerText) {
|
|
684
|
+
var footerEl = document.createElement("div");
|
|
685
|
+
footerEl.className = "aup-list-hero-footer";
|
|
686
|
+
footerEl.textContent = footerText;
|
|
687
|
+
content.appendChild(footerEl);
|
|
688
|
+
}
|
|
689
|
+
hero.appendChild(content);
|
|
690
|
+
return hero;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
function renderStyledItem(entry, strategy, t) {
|
|
694
|
+
switch (itemStyle) {
|
|
695
|
+
case "card": return renderItemCard(entry, strategy, t);
|
|
696
|
+
case "compact": return renderItemCompact(entry, strategy, t);
|
|
697
|
+
case "media": return renderItemMedia(entry, strategy, t);
|
|
698
|
+
case "hero": return renderItemHero(entry, strategy, t);
|
|
699
|
+
default: return renderItemRow(entry, strategy, t);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// ── Table Rendering ──
|
|
704
|
+
function renderTable(entries, expandable) {
|
|
705
|
+
var table = document.createElement("table");
|
|
706
|
+
table.className = "aup-list-table";
|
|
707
|
+
var thead = document.createElement("thead");
|
|
708
|
+
var headerRow = document.createElement("tr");
|
|
709
|
+
var cols = columns || [{ key: "id", label: "Name" }];
|
|
710
|
+
if (expandable) {
|
|
711
|
+
var thExpand = document.createElement("th");
|
|
712
|
+
thExpand.style.width = "28px";
|
|
713
|
+
headerRow.appendChild(thExpand);
|
|
714
|
+
}
|
|
715
|
+
for (var ci = 0; ci < cols.length; ci++) {
|
|
716
|
+
var th = document.createElement("th");
|
|
717
|
+
th.textContent = cols[ci].label || cols[ci].key;
|
|
718
|
+
if (cols[ci].width) th.style.width = cols[ci].width;
|
|
719
|
+
if (cols[ci].align) th.style.textAlign = cols[ci].align;
|
|
720
|
+
headerRow.appendChild(th);
|
|
721
|
+
}
|
|
722
|
+
thead.appendChild(headerRow);
|
|
723
|
+
table.appendChild(thead);
|
|
724
|
+
var tbody = document.createElement("tbody");
|
|
725
|
+
renderTableRows(entries, tbody, cols, 0, expandable);
|
|
726
|
+
table.appendChild(tbody);
|
|
727
|
+
return table;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function renderTableRows(entries, tbody, cols, depth, expandable) {
|
|
731
|
+
for (var ri = 0; ri < entries.length; ri++) {
|
|
732
|
+
var entry = entries[ri];
|
|
733
|
+
var tr = document.createElement("tr");
|
|
734
|
+
tr.className = "aup-list-table-row";
|
|
735
|
+
tr.setAttribute("data-depth", String(depth));
|
|
736
|
+
var entryPath = _buildEntryPath(entry, _currentPath);
|
|
737
|
+
var isDir = _listIsDirectory(entry);
|
|
738
|
+
if (_selectedId === entry.id) tr.setAttribute("data-selected", "true");
|
|
739
|
+
|
|
740
|
+
if (expandable) {
|
|
741
|
+
var tdExp = document.createElement("td");
|
|
742
|
+
tdExp.className = "aup-list-table-expand";
|
|
743
|
+
tdExp.style.paddingLeft = (8 + depth * 16) + "px";
|
|
744
|
+
if (isDir && depth < maxDepth) {
|
|
745
|
+
var chevron = document.createElement("span");
|
|
746
|
+
chevron.className = "aup-list-chevron";
|
|
747
|
+
chevron.textContent = _expanded[entryPath] ? "\\u25BC" : "\\u25B6";
|
|
748
|
+
tdExp.appendChild(chevron);
|
|
749
|
+
(function(ent, ep, d) {
|
|
750
|
+
tdExp.onclick = function(e) {
|
|
751
|
+
e.stopPropagation();
|
|
752
|
+
toggleGroup(ent, ep, d);
|
|
753
|
+
};
|
|
754
|
+
})(entry, entryPath, depth);
|
|
755
|
+
}
|
|
756
|
+
tr.appendChild(tdExp);
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
for (var cj = 0; cj < cols.length; cj++) {
|
|
760
|
+
var td = document.createElement("td");
|
|
761
|
+
var cellVal = _listResolveField(entry, cols[cj].key) || "";
|
|
762
|
+
td.textContent = cellVal;
|
|
763
|
+
if (cols[cj].align) td.style.textAlign = cols[cj].align;
|
|
764
|
+
tr.appendChild(td);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
(function(ent, ep) {
|
|
768
|
+
tr.onclick = function(e) {
|
|
769
|
+
if (e.target.closest && e.target.closest(".aup-list-table-expand")) return;
|
|
770
|
+
_selectedId = ent.id;
|
|
771
|
+
renderEntries();
|
|
772
|
+
emitEvent("select", { path: ep, id: ent.id, meta: ent.meta || {}, content: ent.content || {} });
|
|
773
|
+
};
|
|
774
|
+
})(entry, entryPath);
|
|
775
|
+
|
|
776
|
+
tbody.appendChild(tr);
|
|
777
|
+
|
|
778
|
+
// Expanded children rows (tree-table)
|
|
779
|
+
if (expandable && isDir && _expanded[entryPath] && _childCache[entryPath]) {
|
|
780
|
+
var childEntries = processPipeline(_childCache[entryPath]);
|
|
781
|
+
renderTableRows(childEntries, tbody, cols, depth + 1, expandable);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// ── Grouped Item Rendering ──
|
|
787
|
+
function renderGroupedItem(entry, parentPath, parentEl, depth) {
|
|
788
|
+
var strategy = _listResolveStrategy(entry);
|
|
789
|
+
var t = entry._transform || {};
|
|
790
|
+
var isDir = _listIsDirectory(entry);
|
|
791
|
+
var canExpand = isDir && depth < maxDepth;
|
|
792
|
+
var entryPath = _buildEntryPath(entry, parentPath);
|
|
793
|
+
|
|
794
|
+
var wrap = document.createElement("div");
|
|
795
|
+
wrap.className = "aup-list-grouped-item";
|
|
796
|
+
wrap.setAttribute("data-depth", String(depth));
|
|
797
|
+
|
|
798
|
+
var header = document.createElement("div");
|
|
799
|
+
header.className = "aup-list-row " + (strategy.cssClass || "");
|
|
800
|
+
header.setAttribute("data-kind", (entry.meta && entry.meta.kind) || "");
|
|
801
|
+
|
|
802
|
+
if (canExpand) {
|
|
803
|
+
var chevron = document.createElement("span");
|
|
804
|
+
chevron.className = "aup-list-chevron";
|
|
805
|
+
chevron.textContent = _expanded[entryPath] ? "\\u25BC" : "\\u25B6";
|
|
806
|
+
header.appendChild(chevron);
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// Reuse the chosen item style but within the grouped row
|
|
810
|
+
var styledEl = renderStyledItem(entry, strategy, t);
|
|
811
|
+
// Extract inner content from styled element to flatten into header
|
|
812
|
+
while (styledEl.firstChild) header.appendChild(styledEl.firstChild);
|
|
813
|
+
|
|
814
|
+
if (_selectedId === entry.id) header.setAttribute("data-selected", "true");
|
|
815
|
+
|
|
816
|
+
header.onclick = function(e) {
|
|
817
|
+
e.stopPropagation();
|
|
818
|
+
if (canExpand) {
|
|
819
|
+
toggleGroup(entry, entryPath, depth);
|
|
820
|
+
} else {
|
|
821
|
+
var shouldNavigate = (clickMode === "navigate" && isDir) || (clickMode === "both" && isDir);
|
|
822
|
+
var shouldSelect = (clickMode === "select") || (clickMode === "both" && !isDir);
|
|
823
|
+
if (shouldNavigate) {
|
|
824
|
+
navigateTo(entryPath + "/", _pathStack.length);
|
|
825
|
+
emitEvent("navigate", { path: entryPath, id: entry.id, meta: entry.meta || {}, previousPath: _currentPath });
|
|
826
|
+
}
|
|
827
|
+
if (shouldSelect || (!shouldNavigate && clickMode !== "navigate")) {
|
|
828
|
+
_selectedId = entry.id;
|
|
829
|
+
renderEntries();
|
|
830
|
+
emitEvent("select", { path: entryPath, id: entry.id, meta: entry.meta || {}, content: entry.content || {} });
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
|
|
835
|
+
wrap.appendChild(header);
|
|
836
|
+
|
|
837
|
+
if (canExpand) {
|
|
838
|
+
var childrenEl = document.createElement("div");
|
|
839
|
+
childrenEl.className = "aup-list-children";
|
|
840
|
+
childrenEl.setAttribute("data-expanded", String(!!_expanded[entryPath]));
|
|
841
|
+
if (_expanded[entryPath] && _childCache[entryPath]) {
|
|
842
|
+
var childEntries = processPipeline(_childCache[entryPath]);
|
|
843
|
+
for (var ci = 0; ci < childEntries.length; ci++) {
|
|
844
|
+
renderGroupedItem(childEntries[ci], entryPath, childrenEl, depth + 1);
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
wrap.appendChild(childrenEl);
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
parentEl.appendChild(wrap);
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// ── Flat Item Rendering ──
|
|
854
|
+
function renderFlatItem(entry, parentPath, parentEl) {
|
|
855
|
+
var strategy = _listResolveStrategy(entry);
|
|
856
|
+
var t = entry._transform || {};
|
|
857
|
+
var kind = (entry.meta && entry.meta.kind) || "";
|
|
858
|
+
var isDir = _listIsDirectory(entry);
|
|
859
|
+
var entryPath = _buildEntryPath(entry, parentPath);
|
|
860
|
+
|
|
861
|
+
var item = renderStyledItem(entry, strategy, t);
|
|
862
|
+
item.setAttribute("data-kind", kind);
|
|
863
|
+
item.style.cursor = "pointer";
|
|
864
|
+
if (_selectedId === entry.id) item.setAttribute("data-selected", "true");
|
|
865
|
+
|
|
866
|
+
item.onclick = function(e) {
|
|
867
|
+
e.stopPropagation();
|
|
868
|
+
var shouldNavigate = (clickMode === "navigate" && isDir) || (clickMode === "both" && isDir);
|
|
869
|
+
var shouldSelect = (clickMode === "select") || (clickMode === "both" && !isDir);
|
|
870
|
+
if (shouldNavigate) {
|
|
871
|
+
navigateTo(entryPath + "/", _pathStack.length);
|
|
872
|
+
emitEvent("navigate", { path: entryPath, id: entry.id, meta: entry.meta || {}, previousPath: _currentPath });
|
|
873
|
+
}
|
|
874
|
+
if (shouldSelect || (!shouldNavigate && clickMode !== "navigate")) {
|
|
875
|
+
_selectedId = entry.id;
|
|
876
|
+
renderEntries();
|
|
877
|
+
emitEvent("select", { path: entryPath, id: entry.id, meta: entry.meta || {}, content: entry.content || {} });
|
|
878
|
+
}
|
|
879
|
+
};
|
|
880
|
+
|
|
881
|
+
parentEl.appendChild(item);
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
// ── Slideshow ──
|
|
885
|
+
function slideTo(idx) {
|
|
886
|
+
var items = bodyEl.children;
|
|
887
|
+
if (!items.length) return;
|
|
888
|
+
_slideIndex = Math.max(0, Math.min(idx, items.length - 1));
|
|
889
|
+
for (var i = 0; i < items.length; i++) {
|
|
890
|
+
items[i].style.display = i === _slideIndex ? "" : "none";
|
|
891
|
+
}
|
|
892
|
+
if (slideshowNav) {
|
|
893
|
+
var counter = slideshowNav.querySelector(".aup-list-slide-counter");
|
|
894
|
+
if (counter) counter.textContent = (_slideIndex + 1) + " / " + items.length;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
// ── Virtual Scroll Math ──
|
|
899
|
+
function _vsFindStartIndex(scrollTop) {
|
|
900
|
+
var acc = 0;
|
|
901
|
+
for (var i = 0; i < _entries.length; i++) {
|
|
902
|
+
var h = _itemHeights[i] || _estimatedHeight;
|
|
903
|
+
if (acc + h > scrollTop) return i;
|
|
904
|
+
acc += h;
|
|
905
|
+
}
|
|
906
|
+
return Math.max(0, _entries.length - 1);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
function _vsSumHeights(from, to) {
|
|
910
|
+
var sum = 0;
|
|
911
|
+
for (var i = from; i < to; i++) {
|
|
912
|
+
sum += _itemHeights[i] || _estimatedHeight;
|
|
913
|
+
}
|
|
914
|
+
return sum;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
var _vsTopSpacer = null;
|
|
918
|
+
var _vsBottomSpacer = null;
|
|
919
|
+
var _vsContentEl = null;
|
|
920
|
+
var _vsScrollHandler = null;
|
|
921
|
+
|
|
922
|
+
if (_virtual) {
|
|
923
|
+
bodyEl.style.overflow = "auto";
|
|
924
|
+
bodyEl.style.position = "relative";
|
|
925
|
+
_vsTopSpacer = document.createElement("div");
|
|
926
|
+
_vsTopSpacer.className = "aup-list-virtual-spacer";
|
|
927
|
+
_vsBottomSpacer = document.createElement("div");
|
|
928
|
+
_vsBottomSpacer.className = "aup-list-virtual-spacer";
|
|
929
|
+
_vsContentEl = document.createElement("div");
|
|
930
|
+
_vsContentEl.className = "aup-list-virtual-content";
|
|
931
|
+
|
|
932
|
+
_vsScrollHandler = function() {
|
|
933
|
+
_renderVirtualRange();
|
|
934
|
+
};
|
|
935
|
+
bodyEl.addEventListener("scroll", _vsScrollHandler);
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
function _renderVirtualRange() {
|
|
939
|
+
if (!_virtual || !_vsContentEl) return;
|
|
940
|
+
var processed = processPipeline(_entries);
|
|
941
|
+
if (processed.length === 0) return;
|
|
942
|
+
|
|
943
|
+
var scrollTop = bodyEl.scrollTop;
|
|
944
|
+
var viewportH = bodyEl.clientHeight;
|
|
945
|
+
|
|
946
|
+
var rawStart = _vsFindStartIndex(scrollTop);
|
|
947
|
+
var rawEnd = rawStart;
|
|
948
|
+
var acc = 0;
|
|
949
|
+
for (var i = rawStart; i < processed.length; i++) {
|
|
950
|
+
acc += _itemHeights[i] || _estimatedHeight;
|
|
951
|
+
rawEnd = i;
|
|
952
|
+
if (acc >= viewportH) break;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
var startIdx = Math.max(0, rawStart - _bufferItems);
|
|
956
|
+
var endIdx = Math.min(processed.length - 1, rawEnd + _bufferItems);
|
|
957
|
+
|
|
958
|
+
// Check if range changed
|
|
959
|
+
if (_virtualRenderedRange &&
|
|
960
|
+
_virtualRenderedRange[0] === startIdx &&
|
|
961
|
+
_virtualRenderedRange[1] === endIdx) {
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
_virtualRenderedRange = [startIdx, endIdx];
|
|
965
|
+
|
|
966
|
+
// Update spacers
|
|
967
|
+
_vsTopSpacer.style.height = _vsSumHeights(0, startIdx) + "px";
|
|
968
|
+
_vsBottomSpacer.style.height = _vsSumHeights(endIdx + 1, processed.length) + "px";
|
|
969
|
+
|
|
970
|
+
// Render visible items
|
|
971
|
+
_vsContentEl.innerHTML = "";
|
|
972
|
+
for (var vi = startIdx; vi <= endIdx; vi++) {
|
|
973
|
+
var vEntry = processed[vi];
|
|
974
|
+
renderFlatItem(vEntry, _currentPath, _vsContentEl);
|
|
975
|
+
// Measure item height after render
|
|
976
|
+
var lastChild = _vsContentEl.lastElementChild;
|
|
977
|
+
if (lastChild) {
|
|
978
|
+
_itemHeights[vi] = lastChild.offsetHeight || _estimatedHeight;
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// Pagination: trigger fetch when near end
|
|
983
|
+
if (pageSize > 0 && endIdx >= _loadedCount - _bufferItems && _loadedCount < _total && !_loadingMore) {
|
|
984
|
+
fetchPage(_currentPath, _loadedCount, false);
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
// ── Main Render ──
|
|
989
|
+
function renderEntries() {
|
|
990
|
+
bodyEl.innerHTML = "";
|
|
991
|
+
|
|
992
|
+
// Header template
|
|
993
|
+
if (_headerTemplate && typeof renderAupNode === "function") {
|
|
994
|
+
var headerBound = JSON.parse(JSON.stringify(_headerTemplate));
|
|
995
|
+
headerBound.id = (_headerTemplate.id || "header") + "--header";
|
|
996
|
+
var headerEl = renderAupNode(headerBound);
|
|
997
|
+
if (headerEl) {
|
|
998
|
+
headerEl.classList.add("aup-list-template-header");
|
|
999
|
+
bodyEl.appendChild(headerEl);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
var processed = processPipeline(_entries);
|
|
1004
|
+
if (processed.length === 0) {
|
|
1005
|
+
// Empty template or default
|
|
1006
|
+
if (_emptyTemplate && typeof renderAupNode === "function") {
|
|
1007
|
+
var emptyBound = JSON.parse(JSON.stringify(_emptyTemplate));
|
|
1008
|
+
emptyBound.id = (_emptyTemplate.id || "empty") + "--empty";
|
|
1009
|
+
var emptyNodeEl = renderAupNode(emptyBound);
|
|
1010
|
+
if (emptyNodeEl) {
|
|
1011
|
+
emptyNodeEl.classList.add("aup-list-template-empty");
|
|
1012
|
+
bodyEl.appendChild(emptyNodeEl);
|
|
1013
|
+
}
|
|
1014
|
+
} else {
|
|
1015
|
+
var empty = document.createElement("div");
|
|
1016
|
+
empty.className = "aup-list-empty";
|
|
1017
|
+
empty.textContent = _filterQuery ? "No matches" : emptyText;
|
|
1018
|
+
bodyEl.appendChild(empty);
|
|
1019
|
+
}
|
|
1020
|
+
if (slideshowNav) slideshowNav.style.display = "none";
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
// Virtual scroll mode
|
|
1025
|
+
if (_virtual && _vsTopSpacer && _vsBottomSpacer && _vsContentEl) {
|
|
1026
|
+
bodyEl.appendChild(_vsTopSpacer);
|
|
1027
|
+
bodyEl.appendChild(_vsContentEl);
|
|
1028
|
+
bodyEl.appendChild(_vsBottomSpacer);
|
|
1029
|
+
_virtualRenderedRange = null;
|
|
1030
|
+
_renderVirtualRange();
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
// Three-layer template resolution: role="item" > kind registry > built-in
|
|
1035
|
+
// _resolveTemplate returns a template node or null (null = use built-in)
|
|
1036
|
+
function _resolveTemplate(entry) {
|
|
1037
|
+
// Priority 1: explicit role="item" child
|
|
1038
|
+
if (_itemTemplate) return _itemTemplate;
|
|
1039
|
+
// Priority 2: kind registry
|
|
1040
|
+
if (window.aup && window.aup.getKindTemplate) {
|
|
1041
|
+
var entryKind = (entry.meta && entry.meta.kind) || "";
|
|
1042
|
+
var kindTpl = window.aup.getKindTemplate(entryKind);
|
|
1043
|
+
if (kindTpl) return kindTpl;
|
|
1044
|
+
}
|
|
1045
|
+
// Priority 3: built-in
|
|
1046
|
+
return null;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// Check if ANY entry has a template (to decide render path)
|
|
1050
|
+
var _useTemplateMode = false;
|
|
1051
|
+
if (typeof renderAupNode === "function") {
|
|
1052
|
+
if (_itemTemplate) {
|
|
1053
|
+
_useTemplateMode = true;
|
|
1054
|
+
} else if (window.aup && window.aup.getKindTemplate) {
|
|
1055
|
+
for (var ci = 0; ci < processed.length; ci++) {
|
|
1056
|
+
if (_resolveTemplate(processed[ci])) { _useTemplateMode = true; break; }
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
if (_useTemplateMode) {
|
|
1062
|
+
for (var ti = 0; ti < processed.length; ti++) {
|
|
1063
|
+
var tEntry = processed[ti];
|
|
1064
|
+
var tpl = _resolveTemplate(tEntry);
|
|
1065
|
+
if (tpl) {
|
|
1066
|
+
var boundNode = _bindTemplate(tpl, tEntry);
|
|
1067
|
+
var tplEl = renderAupNode(boundNode);
|
|
1068
|
+
if (tplEl) {
|
|
1069
|
+
tplEl.classList.add("aup-list-template-item");
|
|
1070
|
+
(function(entry) {
|
|
1071
|
+
tplEl.addEventListener("click", function() {
|
|
1072
|
+
_selectedId = entry.id;
|
|
1073
|
+
emitEvent("select", { path: entry.path, id: entry.id, meta: entry.meta, content: entry.content });
|
|
1074
|
+
});
|
|
1075
|
+
})(tEntry);
|
|
1076
|
+
bodyEl.appendChild(tplEl);
|
|
1077
|
+
}
|
|
1078
|
+
} else {
|
|
1079
|
+
// Fallback to built-in for entries without template
|
|
1080
|
+
renderFlatItem(tEntry, _currentPath, bodyEl);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
} else if (layout === "table") {
|
|
1084
|
+
bodyEl.appendChild(renderTable(processed, isGrouped));
|
|
1085
|
+
} else if (isGrouped) {
|
|
1086
|
+
for (var i = 0; i < processed.length; i++) {
|
|
1087
|
+
renderGroupedItem(processed[i], _currentPath, bodyEl, 0);
|
|
1088
|
+
}
|
|
1089
|
+
} else {
|
|
1090
|
+
for (var i = 0; i < processed.length; i++) {
|
|
1091
|
+
renderFlatItem(processed[i], _currentPath, bodyEl);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
if (layout === "slideshow") {
|
|
1096
|
+
slideTo(_slideIndex);
|
|
1097
|
+
if (slideshowNav) slideshowNav.style.display = "";
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
// Pagination: "Load more" button
|
|
1101
|
+
if (pageSize > 0 && _loadedCount < _total) {
|
|
1102
|
+
var moreEl = document.createElement("div");
|
|
1103
|
+
moreEl.className = "aup-list-load-more";
|
|
1104
|
+
moreEl.textContent = "Load more (" + _loadedCount + " of " + _total + ")";
|
|
1105
|
+
moreEl.addEventListener("click", function() {
|
|
1106
|
+
if (!_loadingMore) {
|
|
1107
|
+
moreEl.textContent = "Loading...";
|
|
1108
|
+
fetchPage(_currentPath, _loadedCount, false);
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
bodyEl.appendChild(moreEl);
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
// ── Navigation ──
|
|
1116
|
+
function navigateTo(path, stackIdx) {
|
|
1117
|
+
_currentPath = path;
|
|
1118
|
+
if (stackIdx != null && stackIdx < _pathStack.length) {
|
|
1119
|
+
_pathStack = _pathStack.slice(0, stackIdx);
|
|
1120
|
+
}
|
|
1121
|
+
_pathStack.push(path);
|
|
1122
|
+
_selectedId = null;
|
|
1123
|
+
_expanded = {};
|
|
1124
|
+
_childCache = {};
|
|
1125
|
+
_slideIndex = 0;
|
|
1126
|
+
fetchAndRender(path);
|
|
1127
|
+
subscribePath(path);
|
|
1128
|
+
renderBreadcrumb();
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// ── Group Toggle ──
|
|
1132
|
+
function toggleGroup(entry, entryPath, depth) {
|
|
1133
|
+
var wasExpanded = !!_expanded[entryPath];
|
|
1134
|
+
_expanded[entryPath] = !wasExpanded;
|
|
1135
|
+
|
|
1136
|
+
if (!wasExpanded && !_childCache[entryPath]) {
|
|
1137
|
+
window.afs.list(entryPath + "/").then(function(result) {
|
|
1138
|
+
var data = result && result.data ? result.data : (Array.isArray(result) ? result : []);
|
|
1139
|
+
_childCache[entryPath] = Array.isArray(data) ? data : [];
|
|
1140
|
+
renderEntries();
|
|
1141
|
+
}).catch(function() {
|
|
1142
|
+
_childCache[entryPath] = [];
|
|
1143
|
+
renderEntries();
|
|
1144
|
+
});
|
|
1145
|
+
emitEvent("expand", { path: entryPath, id: entry.id, childrenCount: entry.meta && entry.meta.childrenCount });
|
|
1146
|
+
} else {
|
|
1147
|
+
renderEntries();
|
|
1148
|
+
emitEvent(wasExpanded ? "collapse" : "expand", { path: entryPath, id: entry.id });
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
// ── Data Fetching ──
|
|
1153
|
+
function fetchAndRender(path) {
|
|
1154
|
+
_entries = [];
|
|
1155
|
+
_total = 0;
|
|
1156
|
+
_loadedCount = 0;
|
|
1157
|
+
fetchPage(path, 0, true);
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
function fetchPage(path, offset, isInitial) {
|
|
1161
|
+
if (isInitial) {
|
|
1162
|
+
loadingEl.style.display = "block";
|
|
1163
|
+
bodyEl.style.display = "none";
|
|
1164
|
+
}
|
|
1165
|
+
_loadingMore = true;
|
|
1166
|
+
var opts = pageSize > 0 ? { offset: offset, limit: pageSize } : {};
|
|
1167
|
+
window.afs.list(path, opts).then(function(result) {
|
|
1168
|
+
// Handle both new { data, total } format and legacy array format
|
|
1169
|
+
var data = result && result.data ? result.data : (Array.isArray(result) ? result : []);
|
|
1170
|
+
var newEntries = Array.isArray(data) ? data : [];
|
|
1171
|
+
if (offset === 0) {
|
|
1172
|
+
_entries = newEntries;
|
|
1173
|
+
} else {
|
|
1174
|
+
_entries = _entries.concat(newEntries);
|
|
1175
|
+
}
|
|
1176
|
+
_total = result && result.total != null ? result.total : _entries.length;
|
|
1177
|
+
_loadedCount = _entries.length;
|
|
1178
|
+
_loadingMore = false;
|
|
1179
|
+
if (isInitial) {
|
|
1180
|
+
loadingEl.style.display = "none";
|
|
1181
|
+
bodyEl.style.display = "";
|
|
1182
|
+
}
|
|
1183
|
+
renderEntries();
|
|
1184
|
+
}).catch(function(e) {
|
|
1185
|
+
_loadingMore = false;
|
|
1186
|
+
if (isInitial) {
|
|
1187
|
+
var errStr = String(e && e.message || e || "");
|
|
1188
|
+
if (errStr.indexOf("not found") >= 0 || errStr.indexOf("Not found") >= 0 || errStr.indexOf("Path not found") >= 0) {
|
|
1189
|
+
loadingEl.textContent = "This entry cannot be browsed as a directory";
|
|
1190
|
+
} else {
|
|
1191
|
+
loadingEl.textContent = "Unable to list: " + (errStr || "unknown error");
|
|
1192
|
+
}
|
|
1193
|
+
bodyEl.style.display = "none";
|
|
1194
|
+
}
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
// ── Live Subscription ──
|
|
1199
|
+
function subscribePath(path) {
|
|
1200
|
+
if (_unsubscribe) _unsubscribe();
|
|
1201
|
+
if (window.afs && window.afs.subscribe) {
|
|
1202
|
+
_unsubscribe = window.afs.subscribe(
|
|
1203
|
+
{ type: "afs:write", path: path },
|
|
1204
|
+
function() { fetchAndRender(_currentPath); }
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
// ── Event Emission ──
|
|
1210
|
+
function emitEvent(eventName, data) {
|
|
1211
|
+
if (ws && ws.readyState === 1) {
|
|
1212
|
+
ws.send(JSON.stringify({
|
|
1213
|
+
type: "aup_event",
|
|
1214
|
+
nodeId: node.id,
|
|
1215
|
+
event: eventName,
|
|
1216
|
+
data: data
|
|
1217
|
+
}));
|
|
1218
|
+
}
|
|
1219
|
+
// Also dispatch DOM CustomEvent for client-side listeners (e.g., device surface)
|
|
1220
|
+
el.dispatchEvent(new CustomEvent("aup-list:" + eventName, { detail: data, bubbles: true }));
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
// ── Initial Load ──
|
|
1224
|
+
if (node.src && window.afs) {
|
|
1225
|
+
fetchAndRender(_currentPath);
|
|
1226
|
+
subscribePath(_currentPath);
|
|
1227
|
+
renderBreadcrumb();
|
|
1228
|
+
} else {
|
|
1229
|
+
loadingEl.style.display = "none";
|
|
1230
|
+
bodyEl.style.display = "";
|
|
1231
|
+
var empty = document.createElement("div");
|
|
1232
|
+
empty.className = "aup-list-empty";
|
|
1233
|
+
empty.textContent = node.src ? "Connecting..." : emptyText;
|
|
1234
|
+
bodyEl.appendChild(empty);
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
return el;
|
|
1238
|
+
}
|
|
1239
|
+
`;
|
|
1240
|
+
|
|
1241
|
+
//#endregion
|
|
1242
|
+
export { LIST_JS };
|
|
1243
|
+
//# sourceMappingURL=list.mjs.map
|