اگر کاربر فرد را اشتباه تشخیص داده (مثلاً فردی که از قبل در فهرست است را بهعنوان فرد جدید پیشنهاد کرده)، بهجای رد کردن میتوانید آن را به فرد موجود متصل کنید؛
برای فرد تازه فقط نام قابل اصلاح است - اصلاح روابط/تاریخها نیازمند رد کردن و ارسال دوبارهٔ پیشنهاد توسط کاربر است:
اگر کاربر شخصیت را اشتباه تشخیص داده (مثلاً شخصیتی که از قبل در فهرست است را بهعنوان شخصیت جدید پیشنهاد کرده)، بهجای رد کردن میتوانید آن را به شخصیت موجود متصل کنید؛
برای شخصیت تازه فقط نام قابل اصلاح است - اصلاح روابط/تاریخها نیازمند رد کردن و ارسال دوبارهٔ پیشنهاد توسط کاربر است:
</p>
<label for="geotag@(geoIndex)_person_search">اتصال به فرد موجود در فهرست (در صورت وجود اشتباه در تشخیص فرد):</label>
<label for="geotag@(geoIndex)_person_search">اتصال به شخصیت موجود در فهرست (در صورت وجود اشتباه در تشخیص شخصیت):</label>
<div class="up-autocomplete-wrap">
<input type="text" id="geotag@(geoIndex)_person_search" autocomplete="off" placeholder="نام فرد را تایپ کنید..."
<input type="text" id="geotag@(geoIndex)_person_search" autocomplete="off" placeholder="نام شخصیت را تایپ کنید..."
<p class="up-hint">برای اتصال به یک فرد موجود، نام او را تایپ کنید و از فهرست انتخاب کنید؛ برای رها کردن اتصال و پیشنهاد بهعنوان فرد جدید، این فیلد را خالی کنید.</p>
<p class="up-hint">برای اتصال به یک شخصیت موجود، نام او را تایپ کنید و از فهرست انتخاب کنید؛ برای رها کردن اتصال و پیشنهاد بهعنوان شخصیت جدید، این فیلد را خالی کنید.</p>
// staged client-side until the main save; each item matches
// GanjoorPoemGeoDateTagCorrection's shape so it can be sent as-is
// ---------- geo/date tag AND person (شخصیت) tag suggestions ----------
// Both kinds are staged client-side (until the main save) in this ONE combined array, and both
// are sent to the server as one flat GanjoorPoemGeoDateTagCorrection[] (pcs.geoDateTags) - that
// part of the data model is shared, on purpose (see the doc comment on
// GanjoorPoemGeoDateTagCorrection.SuggestedPersonGraphJson). But a geo/date tag and a person tag
// mean unrelated things to a reader ("this couplet refers to this place/time" vs "this couplet
// refers to this person"), so the UI never mixes them in one row: every staged/loaded item here
// carries a client-only "_uiKind" field ('geo' or 'person', added by _getSuggestionUiKind for
// anything that doesn't already have it - e.g. a draft loaded from the server) that the two
// render functions (renderPendingGeoDateTags / renderPendingPersonTags) filter on, and the two
// "add a tag" cards each read/write only their own half of the form.
var geoDateTagSuggestions = @Html.Raw(Model.MyLastEditGeoDateTagsJson);
var geoDateTagCoupletTexts = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Couplets.ToDictionary(c => c.Item1.ToString(), c => c.Item2)));
// full existing-location catalog ({id, name, latitude, longitude}[]), used to warn about a
@ -127,8 +135,28 @@
// full existing-people catalog ({id, name, birthYearInLHijri, deathYearInLHijri}[]), used both
// to pick an existing person for a tag and as the "other side" of a new person's relatives
var allGeoPeople = @Html.Raw(Model.AllPeopleJson);
// {id, personId}[] for this poem's already-approved geo/date/person tags - used only to work out
// the _uiKind of a "delete this existing tag" suggestion loaded from a saved-but-unsubmitted
// draft, which otherwise carries nothing but the id being deleted
var allExistingGeoDateTags = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(
(Model.PoemGeoDateTags ?? Array.Empty<RMuseum.Models.Ganjoor.PoemGeoDateTag>()).Select(t => new { id = t.Id, personId = t.PersonId })));
// Works out whether a staged/loaded suggestion is a geo/date tag or a person (شخصیت) tag, for the
// two render functions to filter on. New items always set _uiKind themselves when pushed; this
// is only needed for items loaded from Model.MyLastEditGeoDateTagsJson (an unsubmitted draft
// from a previous visit), which predate the split and never carry it.
upToast('این فرد در فهرست نیست. طرف دیگر یک رابطه باید از قبل تعریفشده باشد؛ برای دو فرد تازه، ابتدا این فرم را برای یکی از آنها بهصورت جدا تکمیل و ثبت کنید.', 'error');
upToast('این شخصیت در فهرست نیست. طرف دیگر یک رابطه باید از قبل تعریفشده باشد؛ برای دو شخصیت تازه، ابتدا این فرم را برای یکی از آنها بهصورت جدا تکمیل و ثبت کنید.', 'error');
}
);
}
@ -456,7 +484,7 @@
function buildPersonGraphJson() {
var name = ($('#geotag-new-person-name').val() || '').trim();
if (name == '') {
upToast('لطفاً نام فرد جدید را وارد کنید.', 'error');
upToast('لطفاً نام شخصیت جدید را وارد کنید.', 'error');
return null;
}
@ -487,7 +515,7 @@
var idx = rows[r].id.replace('person-relative-row-', '');
var otherPersonId = $('#person-relative-person-id-' + idx).val();
if (!otherPersonId) {
upToast('برای یکی از روابط افزودهشده، فرد دیگر انتخاب نشده است.', 'error');
upToast('برای یکی از روابط افزودهشده، شخصیت دیگر انتخاب نشده است.', 'error');
return null;
}
otherPersonId = parseInt(otherPersonId);
@ -532,30 +560,61 @@
function renderPendingGeoDateTags() {
var container = document.getElementById('pending-geotag-suggestions');
if (geoDateTagSuggestions.length == 0) {
var rows = [];
for (var i = 0; i < geoDateTagSuggestions.length; i++) {
if (_getSuggestionUiKind(geoDateTagSuggestions[i]) === 'geo') rows.push(i);
}
if (rows.length == 0) {
container.innerHTML = '';
return;
}
var html = '<table><tr><th>وضعیت</th><th>بیت</th><th>مکان</th><th>فرد</th><th>سال</th><th>ماه</th><th>روز</th><th>#</th></tr>';
for (var i = 0; i < geoDateTagSuggestions.length; i++) {
var html = '<table><tr><th>وضعیت</th><th>بیت</th><th>مکان</th><th>سال</th><th>ماه</th><th>روز</th><th>#</th></tr>';
for (var r = 0; r < rows.length; r++) {
var i = rows[r];
var s = geoDateTagSuggestions[i];
var status = s.markForDelete ? '🗑️ درخواست حذف' : '➕ پیشنهاد جدید';
var coupletText = (s.coupletIndex != null && geoDateTagCoupletTexts[s.coupletIndex]) ? geoDateTagCoupletTexts[s.coupletIndex] : '— کل شعر —';
<h2 class="up-card__title">🗺️ برچسبهای زمان و مکان (پیشنهادی)</h2>
<p class="up-hint">میتوانید پیشنهاد دهید که این شعر به مکان یا تاریخ خاصی اشاره دارد. پیشنهادهای شما پس از بررسی ناظران اعمال خواهد شد. با دکمهٔ «ذخیره» بالا همراه با بقیهٔ تغییرات ثبت میشود.</p>
<p class="up-hint">میتوانید پیشنهاد دهید که این شعر به یک شخصیت (تاریخی یا داستانی) اشاره دارد. پیشنهادهای شما پس از بررسی ناظران اعمال خواهد شد. با دکمهٔ «ذخیره» بالا همراه با بقیهٔ تغییرات ثبت میشود.</p>
<p class="up-hint">شروع به تایپ کنید تا فهرست افراد بر اساس نام فیلتر شود؛ اگر فرد مورد نظر پیدا نشد، گزینهٔ تعریف او بهعنوان فرد جدید نمایش داده میشود.</p>
<a role="button" class="up-btn up-btn--sm up-btn--ghost" onclick="toggleNewPersonWidget()">👤 فرد جدید پیشنهاد بده</a>
<p class="up-hint">شروع به تایپ کنید تا فهرست شخصیتها بر اساس نام فیلتر شود؛ اگر شخصیت مورد نظر پیدا نشد، گزینهٔ تعریف او بهعنوان شخصیت جدید نمایش داده میشود.</p>
<a role="button" class="up-btn up-btn--sm up-btn--ghost" onclick="toggleNewPersonWidget()">👤 شخصیت جدید پیشنهاد بده</a>
<label for="geotag-new-person-familytreecaption">عنوان شجرهنامه (اختیاری، فقط اگر این فرد ریشهٔ یک خانواده/سلسله شناختهشده است - مثلاً «ساسانیان»)</label>
<label for="geotag-new-person-familytreecaption">عنوان شجرهنامه (اختیاری، فقط اگر این شخصیت ریشهٔ یک خانواده/سلسله شناختهشده است - مثلاً «ساسانیان»)</label>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.