From 15c8f8f526abc6aca1f59eda7c07649654fde1c5 Mon Sep 17 00:00:00 2001 From: Hamid Reza Mohammadi Date: Sat, 3 Oct 2026 21:22:12 +0330 Subject: [PATCH] people tags #387 --- .../Pages/SuggestNewPersonRelation.cshtml | 35 +++++++++++++++---- .../Pages/SuggestNewPersonRelation.cshtml.cs | 15 ++++++++ GanjooRazor/wwwroot/js/bk.js | 31 ++++++++++++++++ 3 files changed, 74 insertions(+), 7 deletions(-) diff --git a/GanjooRazor/Areas/User/Pages/SuggestNewPersonRelation.cshtml b/GanjooRazor/Areas/User/Pages/SuggestNewPersonRelation.cshtml index 47126cf7..b892cbe1 100644 --- a/GanjooRazor/Areas/User/Pages/SuggestNewPersonRelation.cshtml +++ b/GanjooRazor/Areas/User/Pages/SuggestNewPersonRelation.cshtml @@ -26,6 +26,12 @@ else

@Html.Raw(Model.LastResult)

} + +
@Html.AntiForgeryToken() @@ -34,13 +40,28 @@ else خویشاوند یا نامبردۀ دیگر: - +
+ + + +
+

+ اگر بیش از یک نامبرده با نام مشابه در فهرست باشد (مثلاً شخصیت‌های شاهنامه)، پس از انتخاب از روی سال تولد/وفات مطمئن شوید + یا با کلیک روی 👁 اطلاعات کامل آن را ببینید. +

+ diff --git a/GanjooRazor/Areas/User/Pages/SuggestNewPersonRelation.cshtml.cs b/GanjooRazor/Areas/User/Pages/SuggestNewPersonRelation.cshtml.cs index 6e9b0dcd..a7bb4387 100644 --- a/GanjooRazor/Areas/User/Pages/SuggestNewPersonRelation.cshtml.cs +++ b/GanjooRazor/Areas/User/Pages/SuggestNewPersonRelation.cshtml.cs @@ -40,6 +40,21 @@ namespace GanjooRazor.Areas.User.Pages public List OtherPeople { get; set; } + /// + /// camelCase JSON of OtherPeople (id/name/birthYearInLHijri/deathYearInLHijri only), used + /// client-side for the search-as-you-type person picker replacing the old plain <select> + /// (see setupPersonAutocomplete in bk.js) - same shape/purpose as + /// ReviewEdits.cshtml.cs's/Editor.cshtml.cs's AllPeopleJson. The catalog can legitimately + /// contain more than one person sharing the same name (e.g. Shahnameh figures), so the + /// picker shows birth/death years as a disambiguating subtitle and a "👁 view full info" link + /// once a candidate is picked. + /// + public string OtherPeopleJson => + JsonConvert.SerializeObject( + (OtherPeople ?? new List()).Select(p => new { p.Id, p.Name, p.BirthYearInLHijri, p.DeathYearInLHijri }), + new JsonSerializerSettings { ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() } + ); + [BindProperty] public int OtherPersonId { get; set; } diff --git a/GanjooRazor/wwwroot/js/bk.js b/GanjooRazor/wwwroot/js/bk.js index 93b8c731..9ef87e54 100644 --- a/GanjooRazor/wwwroot/js/bk.js +++ b/GanjooRazor/wwwroot/js/bk.js @@ -2885,6 +2885,35 @@ function setupLocationAutocomplete(searchInput, hiddenInput, resultsBox, locatio function setupPersonAutocomplete(searchInput, hiddenInput, resultsBox, people, onSelect, onNotFound) { var MAX_RESULTS = 12; + // The birth/death-year subtitle in each dropdown row below helps tell two same-named people + // apart (the Shahnameh/mythological person catalog in particular has several), but it's not + // always enough - two people can share both a name and era, or the subtitle can be blank if + // neither year is recorded. So once a pick is made (or the field already carries one from the + // server, e.g. correcting an existing suggestion), show a small "👁 view full info" link right + // next to the box, opening that exact person's full profile (PersonWindow.open) so whoever is + // picking - or a moderator reviewing someone else's pick - can be sure it's the right person, + // not just one with a matching name/years. + var viewLink = document.createElement('a'); + viewLink.href = 'javascript:void(0)'; + viewLink.className = 'up-icon-btn'; + viewLink.title = 'مشاهدهٔ اطلاعات کامل این شخصیت'; + viewLink.setAttribute('aria-label', 'مشاهدهٔ اطلاعات کامل این شخصیت'); + viewLink.style.marginRight = '4px'; + viewLink.textContent = '👁'; + viewLink.addEventListener('click', function () { + var id = parseInt(hiddenInput.value, 10); + if (id) PersonWindow.open(id); + }); + if (searchInput.parentNode) { + searchInput.parentNode.insertBefore(viewLink, searchInput.nextSibling); + } + + function updateViewLink() { + var id = parseInt(hiddenInput.value, 10); + viewLink.style.display = id ? 'inline' : 'none'; + } + updateViewLink(); // the hidden input may already carry a value set by the server (editing/correcting an existing pick) + function hide() { resultsBox.style.display = 'none'; resultsBox.innerHTML = ''; @@ -2906,6 +2935,7 @@ function setupPersonAutocomplete(searchInput, hiddenInput, resultsBox, people, o function selectPerson(p) { searchInput.value = p.name; hiddenInput.value = String(p.id); + updateViewLink(); hide(); if (onSelect) onSelect(p); } @@ -2953,6 +2983,7 @@ function setupPersonAutocomplete(searchInput, hiddenInput, resultsBox, people, o searchInput.addEventListener('input', function () { hiddenInput.value = ''; // typing invalidates whatever was previously selected + updateViewLink(); var typed = searchInput.value.trim(); if (typed == '') { hide();