86 lines
2.4 KiB
JavaScript
86 lines
2.4 KiB
JavaScript
import { t } from "./i18n.js";
|
|
import { state } from "./state.js";
|
|
|
|
export const sortByName = (items) =>
|
|
(items ?? [])
|
|
.slice()
|
|
.sort((a, b) =>
|
|
a.name.localeCompare(b.name, undefined, { sensitivity: "base" }),
|
|
);
|
|
|
|
export const truncate = (text, max) => {
|
|
if (!text) return "";
|
|
return text.length > max ? `${text.slice(0, max - 1)}...` : text;
|
|
};
|
|
|
|
export const escapeHtml = (value) =>
|
|
(value ?? "")
|
|
.toString()
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """)
|
|
.replace(/'/g, "'");
|
|
|
|
export const safeUrl = (url) => {
|
|
if (!url) return null;
|
|
try {
|
|
const u = new URL(url);
|
|
if (u.protocol === "http:" || u.protocol === "https:") return u.href;
|
|
} catch {
|
|
return null;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
export const cssEscapeUrl = (url) => url.replace(/['")\\]/g, "\\$&");
|
|
|
|
export function linkRootId(s) {
|
|
return s?.parentSuggestionId ?? s?.id;
|
|
}
|
|
|
|
export function linkedPeerIds(s) {
|
|
if (!s) return [];
|
|
if (Array.isArray(s.linkedIds) && s.linkedIds.length > 0) {
|
|
return s.linkedIds.filter((id) => id !== s.id);
|
|
}
|
|
if (!state.allSuggestions?.length) return [];
|
|
const root = linkRootId(s);
|
|
return state.allSuggestions
|
|
.filter((other) => linkRootId(other) === root && other.id !== s.id)
|
|
.map((other) => other.id);
|
|
}
|
|
|
|
export function linkedPeerTitles(s) {
|
|
if (!s) return [];
|
|
if (Array.isArray(s.linkedTitles) && s.linkedTitles.length > 0) {
|
|
return s.linkedTitles;
|
|
}
|
|
if (!state.allSuggestions?.length) return [];
|
|
const root = linkRootId(s);
|
|
return state.allSuggestions
|
|
.filter((other) => linkRootId(other) === root && other.id !== s.id)
|
|
.map((other) => other.name);
|
|
}
|
|
|
|
export function isLinked(s) {
|
|
return !!s?.parentSuggestionId || linkedPeerIds(s).length > 0;
|
|
}
|
|
|
|
export function linkTooltip(s) {
|
|
const peers = linkedPeerTitles(s);
|
|
if (peers.length === 0) return t("card.linked");
|
|
return t("card.linkedWith", { names: peers.join(", ") });
|
|
}
|
|
|
|
export function renderLinkBadge(s) {
|
|
if (!isLinked(s)) return "";
|
|
return `<span class="chip icon link-chip" title="${escapeHtml(linkTooltip(s))}">🔗</span>`;
|
|
}
|
|
|
|
export function buildLinkOptionLabel(s) {
|
|
const author = s.author ? ` - ${s.author}` : "";
|
|
const linked = isLinked(s) ? " 🔗" : "";
|
|
return `${s.name}${author}${linked}`;
|
|
}
|