177 lines
5.7 KiB
TypeScript
177 lines
5.7 KiB
TypeScript
import { shallowRef } from "vue";
|
|
|
|
export function defaultAssetKey(asset: Record<string, any> | null | undefined): string {
|
|
if (!asset || typeof asset !== "object") return "";
|
|
return [
|
|
asset.source || asset.type || "output",
|
|
asset.root_id || asset.custom_root_id || "",
|
|
asset.subfolder || "",
|
|
asset.filename || asset.filepath || asset.path || asset.fullpath || asset.full_path || "",
|
|
]
|
|
.join("|")
|
|
.trim()
|
|
.toLowerCase();
|
|
}
|
|
|
|
export function createAssetCollectionIndex(assets: any[] = [], { assetKey = defaultAssetKey } = {}) {
|
|
const byId = new Map();
|
|
const byKey = new Map();
|
|
|
|
for (const asset of Array.isArray(assets) ? assets : []) {
|
|
if (!asset || typeof asset !== "object") continue;
|
|
const id = asset.id == null ? "" : String(asset.id);
|
|
const key = assetKey(asset);
|
|
if (id) byId.set(id, asset);
|
|
if (key) byKey.set(key, asset);
|
|
}
|
|
|
|
return { byId, byKey };
|
|
}
|
|
|
|
export function syncAssetCollectionState(state: any, { assetKey = defaultAssetKey } = {}) {
|
|
if (!state || typeof state !== "object") return state;
|
|
const assets = Array.isArray(state.assets) ? state.assets : [];
|
|
const index = createAssetCollectionIndex(assets, { assetKey });
|
|
state.assetIdSet = new Set(index.byId.keys());
|
|
state.seenKeys = new Set(index.byKey.keys());
|
|
return state;
|
|
}
|
|
|
|
export function removeAssetsFromState(state: any, assetIds: any[] = [], { assetKey = defaultAssetKey } = {}) {
|
|
if (!state || typeof state !== "object") return 0;
|
|
const ids = new Set(
|
|
(Array.isArray(assetIds) ? assetIds : [assetIds])
|
|
.map((raw) => {
|
|
if (raw == null) return "";
|
|
if (typeof raw === "object" && raw?.id != null) return String(raw.id);
|
|
return String(raw);
|
|
})
|
|
.map((value) => value.trim())
|
|
.filter(Boolean),
|
|
);
|
|
if (!ids.size) return 0;
|
|
|
|
let removed = 0;
|
|
state.assets = (Array.isArray(state.assets) ? state.assets : []).filter((asset: any) => {
|
|
const id = asset?.id != null ? String(asset.id) : "";
|
|
if (!id || !ids.has(id)) return true;
|
|
removed += 1;
|
|
return false;
|
|
});
|
|
if (removed > 0) syncAssetCollectionState(state, { assetKey });
|
|
return removed;
|
|
}
|
|
|
|
export function useAssetCollection(options: Record<string, any> = {}) {
|
|
const assetKey = options.assetKey || defaultAssetKey;
|
|
const items = shallowRef<any[]>([]);
|
|
let byId = new Map();
|
|
let byKey = new Map();
|
|
|
|
function rebuildIndex() {
|
|
const index = createAssetCollectionIndex(items.value, { assetKey });
|
|
byId = index.byId;
|
|
byKey = index.byKey;
|
|
}
|
|
|
|
function reset(nextItems: any[] = []) {
|
|
items.value = [];
|
|
byId = new Map();
|
|
byKey = new Map();
|
|
append(nextItems);
|
|
}
|
|
|
|
function append(newAssets: any[] = []) {
|
|
const list = Array.isArray(newAssets) ? newAssets : [];
|
|
if (!list.length) return 0;
|
|
|
|
const next = items.value.slice();
|
|
let added = 0;
|
|
|
|
for (const asset of list) {
|
|
if (!asset || typeof asset !== "object") continue;
|
|
const id = asset.id == null ? "" : String(asset.id);
|
|
const key = assetKey(asset);
|
|
if (id && byId.has(id)) continue;
|
|
if (key && byKey.has(key)) continue;
|
|
|
|
next.push(asset);
|
|
if (id) byId.set(id, asset);
|
|
if (key) byKey.set(key, asset);
|
|
added += 1;
|
|
}
|
|
|
|
if (added > 0) {
|
|
items.value = next;
|
|
}
|
|
return added;
|
|
}
|
|
|
|
function upsert(asset: any) {
|
|
if (!asset || typeof asset !== "object") return false;
|
|
const id = asset.id == null ? "" : String(asset.id);
|
|
const key = assetKey(asset);
|
|
const existing = (id && byId.get(id)) || (key && byKey.get(key));
|
|
|
|
if (existing) {
|
|
const previousId = existing.id == null ? "" : String(existing.id);
|
|
const previousKey = assetKey(existing);
|
|
Object.assign(existing, asset);
|
|
const nextKey = assetKey(existing);
|
|
const nextId = existing.id == null ? "" : String(existing.id);
|
|
if (previousId && previousId !== nextId) byId.delete(previousId);
|
|
if (previousKey && previousKey !== nextKey) byKey.delete(previousKey);
|
|
if (nextKey) byKey.set(nextKey, existing);
|
|
if (nextId) byId.set(nextId, existing);
|
|
items.value = items.value.slice();
|
|
return true;
|
|
}
|
|
|
|
return append([asset]) > 0;
|
|
}
|
|
|
|
function remove(assetIds: any[] = []) {
|
|
const ids = new Set(
|
|
(Array.isArray(assetIds) ? assetIds : [assetIds])
|
|
.map((value) => String(value ?? "").trim())
|
|
.filter(Boolean),
|
|
);
|
|
if (!ids.size) return 0;
|
|
|
|
let removed = 0;
|
|
items.value = items.value.filter((asset) => {
|
|
const id = asset?.id == null ? "" : String(asset.id);
|
|
if (!id || !ids.has(id)) return true;
|
|
removed += 1;
|
|
return false;
|
|
});
|
|
if (removed > 0) rebuildIndex();
|
|
return removed;
|
|
}
|
|
|
|
function has(asset: any) {
|
|
if (!asset || typeof asset !== "object") return false;
|
|
const id = asset.id == null ? "" : String(asset.id);
|
|
const key = assetKey(asset);
|
|
return !!((id && byId.has(id)) || (key && byKey.has(key)));
|
|
}
|
|
|
|
function getById(id: any) {
|
|
return byId.get(String(id ?? "")) || null;
|
|
}
|
|
|
|
return {
|
|
items,
|
|
append,
|
|
upsert,
|
|
remove,
|
|
reset,
|
|
has,
|
|
getById,
|
|
rebuildIndex,
|
|
get size() {
|
|
return items.value.length;
|
|
},
|
|
};
|
|
}
|