Schema v${escape(
@@ -589,6 +608,35 @@ export class RevertModal {
);
}
+ const renderFlagStatus = (value, {
+ yesLabel = "Yes",
+ noLabel = "No",
+ unspecifiedLabel = "Not specified",
+ } = {}) => {
+ if (value === true) {
+ return `${escape(yesLabel)}`;
+ }
+ if (value === false) {
+ return `${escape(noLabel)}`;
+ }
+ return this.renderPlaceholder(unspecifiedLabel);
+ };
+
+ const nsfwStatusHtml = renderFlagStatus(version.isNsfw, {
+ yesLabel: "Yes — marked NSFW",
+ noLabel: "No — not flagged as NSFW",
+ unspecifiedLabel: "Not specified",
+ });
+ const kidsStatusHtml = renderFlagStatus(version.isForKids, {
+ yesLabel: "Yes — marked for kids",
+ noLabel: "No — not marked for kids",
+ unspecifiedLabel: "Not specified",
+ });
+
+ const audienceConflictNotice = conflictingAudienceFlags
+ ? 'Conflicting flags detected — this revision is marked both NSFW and for kids. Review before reverting.
'
+ : "";
+
const descriptionHtml = description
? `${escape(description)}
`
: 'No description provided.
';
@@ -718,6 +766,11 @@ export class RevertModal {
definition("Alt text", altHtml, { span: 2 }),
].join("");
+ const audienceRows = [
+ definition("NSFW flag", nsfwStatusHtml),
+ definition("For kids flag", kidsStatusHtml),
+ ].join("");
+
this.details.innerHTML = `
@@ -759,6 +812,14 @@ export class RevertModal {
${descriptionHtml}
+
+ Audience flags
+
+ ${audienceRows}
+
+ ${audienceConflictNotice}
+
+
NIP-71 event metadata
From bc3966798acab0ca4a2e2d3ed67a57930d2d090f Mon Sep 17 00:00:00 2001
From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com>
Date: Thu, 9 Oct 2025 22:41:58 -0400
Subject: [PATCH 2/2] Enforce audience flag exclusivity in edit modal
---
js/ui/components/EditModal.js | 58 +++++++++++++++++++++++++++++++++--
1 file changed, 55 insertions(+), 3 deletions(-)
diff --git a/js/ui/components/EditModal.js b/js/ui/components/EditModal.js
index f65f0f9a..2deef5d2 100644
--- a/js/ui/components/EditModal.js
+++ b/js/ui/components/EditModal.js
@@ -249,9 +249,44 @@ export class EditModal {
});
}
+ if (this.fields.isNsfw && this.fields.isForKids) {
+ this.setupMutuallyExclusiveCheckboxes(
+ this.fields.isNsfw,
+ this.fields.isForKids
+ );
+ }
+
this.nip71FormManager.bindSection(this.nip71SectionKey);
}
+ setupMutuallyExclusiveCheckboxes(firstInput, secondInput) {
+ if (!firstInput || !secondInput) {
+ return;
+ }
+
+ const enforceExclusion = (primary, secondary) => {
+ if (primary.checked) {
+ secondary.checked = false;
+ }
+ };
+
+ const handleFirstChange = () => enforceExclusion(firstInput, secondInput);
+ const handleSecondChange = () => enforceExclusion(secondInput, firstInput);
+
+ if (firstInput.checked && secondInput.checked) {
+ secondInput.checked = false;
+ }
+
+ firstInput.addEventListener("change", handleFirstChange);
+ secondInput.addEventListener("change", handleSecondChange);
+ }
+
+ sanitizeAudienceFlags(flags = {}) {
+ const isNsfw = flags?.isNsfw === true;
+ const isForKids = flags?.isForKids === true && !isNsfw;
+ return { isNsfw, isForKids };
+ }
+
reset() {
if (!this.root) {
this.activeVideo = null;
@@ -322,10 +357,14 @@ export class EditModal {
const enableCommentsValue =
typeof video.enableComments === "boolean" ? video.enableComments : true;
const isPrivateValue = video.isPrivate === true;
- const isNsfwValue =
- typeof video.isNsfw === "boolean" ? video.isNsfw : false;
- const isForKidsValue =
+ const rawIsNsfw = typeof video.isNsfw === "boolean" ? video.isNsfw : false;
+ const rawIsForKids =
typeof video.isForKids === "boolean" ? video.isForKids : false;
+ const { isNsfw: isNsfwValue, isForKids: isForKidsValue } =
+ this.sanitizeAudienceFlags({
+ isNsfw: rawIsNsfw,
+ isForKids: rawIsForKids,
+ });
const editContext = {
...video,
@@ -361,6 +400,13 @@ export class EditModal {
return;
}
+ const sanitizedFlags = this.sanitizeAudienceFlags({
+ isNsfw: editContext.isNsfw,
+ isForKids: editContext.isForKids,
+ });
+ editContext.isNsfw = sanitizedFlags.isNsfw;
+ editContext.isForKids = sanitizedFlags.isForKids;
+
const fieldMap = {
title: editContext.title || "",
url: editContext.url || "",
@@ -831,6 +877,12 @@ export class EditModal {
}
}
+ ({ isNsfw: finalIsNsfw, isForKids: finalIsForKids } =
+ this.sanitizeAudienceFlags({
+ isNsfw: finalIsNsfw,
+ isForKids: finalIsForKids,
+ }));
+
if (!finalTitle || (!finalUrl && !finalMagnet && !hasImetaSource)) {
this.showError(
"Title and at least one of URL, Magnet, or a NIP-71 media variant is required."