Files
olivv-cs-ComfyUI-FunPack/app/legacy/references.js
T
digital-garbageandClaude Sonnet 5 29ac44ffcd feat: v4 UI port Phase A start -- module categories, legacy frontend served live
Two pieces of the "port v4's exact UI onto v5's backend" plan:

- core/contract.py: new optional ModuleSpec.category field (closed set:
  continuity, guidance, conditioning, sampling, post, system), validated in
  core/schema.py, threaded through core/registry.py's FIELDS and
  to_manifest(). Presentation grouping, independent of STAGE (execution
  order) -- a module can be stage="sampling" and category="guidance" at
  once. Only the 4 existing modules that actually render a settings panel
  (alg, sharpen, appearance, full_control) got a category assigned; the
  other 12 have none to categorize (no SETTINGS block) and stay
  uncategorised, which is valid.

- v4's frontend (movie_editor/frontend/*, ~29k lines, 61 files) copied
  verbatim into app/legacy/. core/routes.py's "/" route now serves
  legacy/index.html instead of the composer entry point; a <base> tag in
  that file resolves its own relative script/link tags against
  /funpack/app/legacy/ regardless of what URL it's served at, so every
  file moved as a unit with zero per-file path edits. Verified live: all
  61 assets load 200 OK, the real v4 onboarding screen renders pixel-for-
  pixel (it's the actual DOM/CSS, not a reimplementation), and several v4
  API calls (/api/media, /api/projects, /api/git/status) already succeed
  against v5's real backend by coincidence of shared route naming -- the
  rest 404/405 as expected, since api.js's ~90 functions haven't been
  rewired to v5's actual routes yet (next piece of this plan).

The old composer entry point (app/index.html, app/composer/**) stays in
the tree, unreferenced, until a later cleanup pass once nothing imports it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 23:58:51 +03:00

50 lines
2.1 KiB
JavaScript

// Reference numbering — the "R1, R2, …" a marked media item shows.
//
// The number is counted WITHIN the item's own kind, because that is how a reference slot
// actually resolves: builder._reference_by_slot takes the marks of one kind, in mark order,
// and picks the nth. "Reference video 1" is the first video marked, not the first mark
// overall.
//
// Numbering the marks globally instead made the two disagree, and the disagreement was not
// cosmetic: mark an image and then a video, and the video is labelled R2 everywhere while
// the only slot that can reach it is "Reference video 1". There was no way to have an R1
// video and an R1 image at the same time, so one of a matched pair always looked like the
// second of something.
(function () {
"use strict";
/** Every marked reference of `kind`, in mark order, as media-bin entries. */
function referencesOfKind(marks, bin, kind) {
const byId = new Map((bin || []).map((m) => [m.id, m]));
return (marks || [])
.map((id) => byId.get(id))
.filter((m) => m && (m.kind || "image") === kind);
}
/** The R number this media shows, counted within its own kind. 0 when it is not marked
* (or not in the bin — an id left in the list by a deleted file is not a reference). */
function referenceNumber(marks, bin, mediaId) {
const byId = new Map((bin || []).map((m) => [m.id, m]));
const self = byId.get(mediaId);
if (!self || !(marks || []).includes(mediaId)) return 0;
const kind = self.kind || "image";
let n = 0;
for (const id of marks) {
const m = byId.get(id);
if (!m || (m.kind || "image") !== kind) continue;
n += 1;
if (id === mediaId) return n;
}
return 0;
}
/** How many references share this media's kind — the "of N" half of the badge. */
function referenceCountOfKind(marks, bin, kind) {
return referencesOfKind(marks, bin, kind).length;
}
const api = { referenceNumber, referenceCountOfKind, referencesOfKind };
if (typeof module !== "undefined" && module.exports) module.exports = api;
if (typeof window !== "undefined") window.References = api;
})();