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] 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."