people tags #387
This commit is contained in:
parent
00f98bb611
commit
fecbf0ec3b
@ -113,6 +113,11 @@ else
|
||||
<td>@Model.ImportanceLabel(p.Importance)</td>
|
||||
<td>@Model.ImportanceLabel(s.SuggestedImportance)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>جنسیت</td>
|
||||
<td>@Model.GenderLabel(p.Gender)</td>
|
||||
<td>@Model.GenderLabel(s.SuggestedGender)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>توضیحات</td>
|
||||
<td><small>@p.Description</small></td>
|
||||
|
||||
@ -69,6 +69,19 @@ namespace GanjooRazor.Areas.Admin.Pages
|
||||
}
|
||||
}
|
||||
|
||||
public string GenderLabel(PersonGender gender)
|
||||
{
|
||||
switch (gender)
|
||||
{
|
||||
case PersonGender.Male:
|
||||
return "مرد";
|
||||
case PersonGender.Female:
|
||||
return "زن";
|
||||
default:
|
||||
return "نامشخص";
|
||||
}
|
||||
}
|
||||
|
||||
public IActionResult OnPost()
|
||||
{
|
||||
Skip = string.IsNullOrEmpty(Request.Query["skip"]) ? 0 : int.Parse(Request.Query["skip"]);
|
||||
|
||||
@ -561,7 +561,8 @@
|
||||
birthLocationId: null,
|
||||
deathLocationId: null,
|
||||
familyTreeCaption: $('#geotag-new-person-familytreecaption').val() || null,
|
||||
importance: $('#geotag-new-person-importance').val()
|
||||
importance: $('#geotag-new-person-importance').val(),
|
||||
gender: $('#geotag-new-person-gender').val()
|
||||
};
|
||||
|
||||
var relatedPeople = [];
|
||||
@ -854,6 +855,7 @@
|
||||
$('#geotag-new-person-wikiurl').val('');
|
||||
$('#geotag-new-person-familytreecaption').val('');
|
||||
$('#geotag-new-person-importance').val('Normal');
|
||||
$('#geotag-new-person-gender').val('Unknown');
|
||||
$('#geotag-person-relatives-list').empty();
|
||||
if (document.getElementById('new-person-widget').style.display !== 'none') {
|
||||
toggleNewPersonWidget();
|
||||
@ -2691,6 +2693,15 @@ else
|
||||
</select>
|
||||
<p class="up-hint"><small>فقط اندازهٔ نمایش این نامبرده را در نمودار شخصیتها تعیین میکند.</small></p>
|
||||
</div>
|
||||
<div class="up-field">
|
||||
<label for="geotag-new-person-gender">جنسیت</label>
|
||||
<select id="geotag-new-person-gender">
|
||||
<option value="Unknown" selected="selected">نامشخص</option>
|
||||
<option value="Male">مرد</option>
|
||||
<option value="Female">زن</option>
|
||||
</select>
|
||||
<p class="up-hint"><small>فقط در ترسیم نمودار تبارنامه استفاده میشود (برای تشخیص اینکه کدام والد به عنوان ادامهٔ اصلی شاخهٔ خانوادگی رسم شود).</small></p>
|
||||
</div>
|
||||
|
||||
<p class="up-hint">
|
||||
اگر خویشاوندی یا وابستگی این نامبرده با نامبردۀ دیگری را میدانید، میتوانید همینجا اضافه کنید (نامبردۀ دیگر باید از قبل در فهرست موجود باشد؛
|
||||
|
||||
@ -78,6 +78,19 @@ else
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
جنسیت:
|
||||
<p class="up-hint"><small>صِرفاً در ترسیم نمودار تبارنامه استفاده میشود (برای تشخیص اینکه کدام والد به عنوان ادامهٔ اصلی شاخهٔ خانوادگی رسم شود)؛ در هیچ فهرست یا جستجویی تأثیری ندارد.</small></p>
|
||||
</td>
|
||||
<td>
|
||||
<select asp-for="Suggestion.SuggestedGender">
|
||||
<option value="Unknown">نامشخص</option>
|
||||
<option value="Male">مرد</option>
|
||||
<option value="Female">زن</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>توضیحات:</td>
|
||||
<td><textarea asp-for="Suggestion.SuggestedDescription" rows="10" cols="60"></textarea></td>
|
||||
|
||||
@ -90,6 +90,7 @@ namespace GanjooRazor.Areas.User.Pages
|
||||
SuggestedDeathLocationId = Person.DeathLocationId,
|
||||
SuggestedFamilyTreeCaption = Person.FamilyTreeCaption,
|
||||
SuggestedImportance = Person.Importance,
|
||||
SuggestedGender = Person.Gender,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -79,8 +79,21 @@
|
||||
allIds.forEach(function (id) { isRoot[id] = !parentsOf[id] || parentsOf[id].length === 0; });
|
||||
|
||||
// one child can have two recorded parents (mother + father) - pick a single "primary"
|
||||
// parent per child to build a drawable tree, preferring whichever parent is NOT themselves
|
||||
// a chart-root (so the root-level spouse ends up as the "attached" side, see below)
|
||||
// parent per child to build a drawable tree. Preference order:
|
||||
// 1) whichever parent is NOT themselves a chart-root (so the tree keeps following a
|
||||
// documented lineage instead of dead-ending at a root with no known ancestors) -
|
||||
// the root-level parent then ends up as the "attached" side, see below;
|
||||
// 2) if that's a tie (both parents are roots, or both have their own recorded
|
||||
// ancestors - common in legendary/mythological genealogies where both sides are
|
||||
// fully documented), prefer the father (PersonGender.Male = 1), matching
|
||||
// conventional patrilineal genealogy-chart practice;
|
||||
// 3) if gender doesn't resolve it either (same gender, or neither recorded), fall back
|
||||
// to ascending person id, just to be deterministic - this last step has no meaning
|
||||
// of its own and is only a last resort.
|
||||
function genderRank(id) {
|
||||
var g = (persons[id] && persons[id].gender) || 0;
|
||||
return g === 1 ? 0 : (g === 2 ? 1 : 2); // Male first, then Female, then Unknown
|
||||
}
|
||||
var primaryParentOf = {};
|
||||
var secondaryParentOf = {};
|
||||
allIds.forEach(function (childId) {
|
||||
@ -90,6 +103,8 @@
|
||||
var sorted = ps.slice().sort(function (a, b) {
|
||||
var ar = isRoot[a] ? 1 : 0, br = isRoot[b] ? 1 : 0;
|
||||
if (ar !== br) return ar - br;
|
||||
var ag = genderRank(a), bg = genderRank(b);
|
||||
if (ag !== bg) return ag - bg;
|
||||
return a - b;
|
||||
});
|
||||
primaryParentOf[childId] = sorted[0];
|
||||
@ -202,6 +217,9 @@
|
||||
return { w: baseW + bump.w, h: baseH + bump.h };
|
||||
}
|
||||
|
||||
// 0=Normal (regular weight), 1=Important (semi-bold), 2=VeryImportant (bold)
|
||||
var IMPORTANCE_FONT_WEIGHT = { 0: 400, 1: 600, 2: 700 };
|
||||
|
||||
function renderFamilyTree(containerId, svgId, tooltipId, data, requestedRootId) {
|
||||
var container = document.getElementById(containerId);
|
||||
var svg = document.getElementById(svgId);
|
||||
@ -264,8 +282,12 @@
|
||||
'class': isRequested ? 'ft-box ft-box-current' : 'ft-box'
|
||||
});
|
||||
g.appendChild(rect);
|
||||
// same importance->weight idea as the width/height bump above - Important/VeryImportant
|
||||
// names are drawn bolder, not just in a bigger box, so they stand out at a glance
|
||||
var fontWeight = IMPORTANCE_FONT_WEIGHT[(p && p.importance) || 0] || IMPORTANCE_FONT_WEIGHT[0];
|
||||
var text = el('text', {
|
||||
x: x, y: y + 5, 'text-anchor': 'middle', 'class': 'ft-box-text', direction: 'rtl'
|
||||
x: x, y: y + 5, 'text-anchor': 'middle', 'class': 'ft-box-text', direction: 'rtl',
|
||||
style: 'font-weight:' + fontWeight
|
||||
});
|
||||
text.textContent = personLabel(p);
|
||||
g.appendChild(text);
|
||||
|
||||
6628
RMuseum/Migrations/20261003143457_AddPersonGender.Designer.cs
generated
Normal file
6628
RMuseum/Migrations/20261003143457_AddPersonGender.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
40
RMuseum/Migrations/20261003143457_AddPersonGender.cs
Normal file
40
RMuseum/Migrations/20261003143457_AddPersonGender.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace RMuseum.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddPersonGender : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Gender",
|
||||
table: "GanjoorRelatedPersons",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "SuggestedGender",
|
||||
table: "GanjoorPersonEditSuggestions",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Gender",
|
||||
table: "GanjoorRelatedPersons");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "SuggestedGender",
|
||||
table: "GanjoorPersonEditSuggestions");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1478,6 +1478,9 @@ namespace RMuseum.Migrations
|
||||
b.Property<bool>("SuggestedForDeletion")
|
||||
.HasColumnType("bit");
|
||||
|
||||
b.Property<int>("SuggestedGender")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("SuggestedImportance")
|
||||
.HasColumnType("int");
|
||||
|
||||
@ -2437,6 +2440,9 @@ namespace RMuseum.Migrations
|
||||
b.Property<string>("FamilyTreeCaption")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("Gender")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Importance")
|
||||
.HasColumnType("int");
|
||||
|
||||
|
||||
@ -113,6 +113,11 @@ namespace RMuseum.Models.Ganjoor
|
||||
/// </summary>
|
||||
public PersonImportance SuggestedImportance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// suggested gender (see GanjoorRelatedPerson.Gender)
|
||||
/// </summary>
|
||||
public PersonGender SuggestedGender { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// true if this suggestion is actually a request to delete the person outright, not to
|
||||
/// change their fields - when true, every Suggested* field above is ignored on approval
|
||||
|
||||
@ -84,5 +84,12 @@
|
||||
/// smaller (see PersonImportance and peoplegraph.js's nodeRadius()) - defaults to Normal
|
||||
/// </summary>
|
||||
public PersonImportance Importance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// gender - only used by the family-tree chart to pick which parent is drawn as the tree's
|
||||
/// spine when a child has two recorded parents who both have their own recorded ancestors
|
||||
/// (see PersonGender and familytree.js's buildLayout()) - defaults to Unknown
|
||||
/// </summary>
|
||||
public PersonGender Gender { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
30
RMuseum/Models/Ganjoor/PersonGender.cs
Normal file
30
RMuseum/Models/Ganjoor/PersonGender.cs
Normal file
@ -0,0 +1,30 @@
|
||||
namespace RMuseum.Models.Ganjoor
|
||||
{
|
||||
/// <summary>
|
||||
/// a GanjoorRelatedPerson's gender - used only by the family-tree chart (familytree.js's
|
||||
/// buildLayout()) to break ties when a child has two recorded parents and both happen to have
|
||||
/// their own recorded ancestors (so neither side can be preferred on "continues a documented
|
||||
/// lineage" grounds alone): the father is preferred as the tree's spine parent, matching
|
||||
/// conventional patrilineal genealogy-chart practice, with the mother then drawn attached
|
||||
/// beside him. Never used to filter, rank or otherwise affect query results. New values can be
|
||||
/// appended safely later (stored as int).
|
||||
/// </summary>
|
||||
public enum PersonGender
|
||||
{
|
||||
/// <summary>
|
||||
/// default - not recorded. Falls back to the old ambiguous-tie-break behavior (ascending
|
||||
/// person id) when it matters.
|
||||
/// </summary>
|
||||
Unknown = 0,
|
||||
|
||||
/// <summary>
|
||||
/// male
|
||||
/// </summary>
|
||||
Male = 1,
|
||||
|
||||
/// <summary>
|
||||
/// female
|
||||
/// </summary>
|
||||
Female = 2,
|
||||
}
|
||||
}
|
||||
@ -67,6 +67,12 @@ namespace RMuseum.Models.Ganjoor.ViewModels
|
||||
/// Null/empty is treated as Normal.
|
||||
/// </summary>
|
||||
public string Importance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// name of a PersonGender value ("Unknown", "Male", "Female") - same string-enum convention
|
||||
/// as Importance above. Null/empty is treated as Unknown.
|
||||
/// </summary>
|
||||
public string Gender { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -5010,6 +5010,18 @@
|
||||
<member name="M:RMuseum.Migrations.AddPersonImportance.BuildTargetModel(Microsoft.EntityFrameworkCore.ModelBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="T:RMuseum.Migrations.AddPersonGender">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:RMuseum.Migrations.AddPersonGender.Up(Microsoft.EntityFrameworkCore.Migrations.MigrationBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:RMuseum.Migrations.AddPersonGender.Down(Microsoft.EntityFrameworkCore.Migrations.MigrationBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:RMuseum.Migrations.AddPersonGender.BuildTargetModel(Microsoft.EntityFrameworkCore.ModelBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="T:RMuseum.Models.Accounting.DonationExpenditure">
|
||||
<summary>
|
||||
donation expenditures
|
||||
@ -9534,6 +9546,11 @@
|
||||
suggested importance (see GanjoorRelatedPerson.Importance)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:RMuseum.Models.Ganjoor.GanjoorPersonEditSuggestion.SuggestedGender">
|
||||
<summary>
|
||||
suggested gender (see GanjoorRelatedPerson.Gender)
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:RMuseum.Models.Ganjoor.GanjoorPersonEditSuggestion.SuggestedForDeletion">
|
||||
<summary>
|
||||
true if this suggestion is actually a request to delete the person outright, not to
|
||||
@ -11340,6 +11357,13 @@
|
||||
smaller (see PersonImportance and peoplegraph.js's nodeRadius()) - defaults to Normal
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:RMuseum.Models.Ganjoor.GanjoorRelatedPerson.Gender">
|
||||
<summary>
|
||||
gender - only used by the family-tree chart to pick which parent is drawn as the tree's
|
||||
spine when a child has two recorded parents who both have their own recorded ancestors
|
||||
(see PersonGender and familytree.js's buildLayout()) - defaults to Unknown
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:RMuseum.Models.Ganjoor.GanjoorSiteBanner">
|
||||
<summary>
|
||||
ganjoor.net site banner
|
||||
@ -11907,6 +11931,33 @@
|
||||
doesn't fit any of the above - rely on Note for what the tie actually is
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:RMuseum.Models.Ganjoor.PersonGender">
|
||||
<summary>
|
||||
a GanjoorRelatedPerson's gender - used only by the family-tree chart (familytree.js's
|
||||
buildLayout()) to break ties when a child has two recorded parents and both happen to have
|
||||
their own recorded ancestors (so neither side can be preferred on "continues a documented
|
||||
lineage" grounds alone): the father is preferred as the tree's spine parent, matching
|
||||
conventional patrilineal genealogy-chart practice, with the mother then drawn attached
|
||||
beside him. Never used to filter, rank or otherwise affect query results. New values can be
|
||||
appended safely later (stored as int).
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:RMuseum.Models.Ganjoor.PersonGender.Unknown">
|
||||
<summary>
|
||||
default - not recorded. Falls back to the old ambiguous-tie-break behavior (ascending
|
||||
person id) when it matters.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:RMuseum.Models.Ganjoor.PersonGender.Male">
|
||||
<summary>
|
||||
male
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:RMuseum.Models.Ganjoor.PersonGender.Female">
|
||||
<summary>
|
||||
female
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:RMuseum.Models.Ganjoor.PersonImportance">
|
||||
<summary>
|
||||
how editorially prominent a GanjoorRelatedPerson is treated as - purely a display/sizing
|
||||
@ -15122,6 +15173,12 @@
|
||||
Null/empty is treated as Normal.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:RMuseum.Models.Ganjoor.ViewModels.PersonGraphNode.Gender">
|
||||
<summary>
|
||||
name of a PersonGender value ("Unknown", "Male", "Female") - same string-enum convention
|
||||
as Importance above. Null/empty is treated as Unknown.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:RMuseum.Models.Ganjoor.ViewModels.PersonGraphRelationEntry">
|
||||
<summary>
|
||||
one edge in a PersonGraphSuggestion, between two nodes referenced by their LocalKey (Person1/
|
||||
|
||||
@ -422,6 +422,7 @@ namespace RMuseum.Services.Implementation
|
||||
person.DeathLocationId = suggestion.SuggestedDeathLocationId;
|
||||
person.FamilyTreeCaption = suggestion.SuggestedFamilyTreeCaption;
|
||||
person.Importance = suggestion.SuggestedImportance;
|
||||
person.Gender = suggestion.SuggestedGender;
|
||||
// Id and MachineGenerated on the person are intentionally left untouched
|
||||
}
|
||||
}
|
||||
|
||||
@ -108,7 +108,7 @@ namespace RMuseum.Services.Implementation
|
||||
if(dbCorrection.SummaryReviewResult == CorrectionReviewResult.Approved)
|
||||
{
|
||||
dbCorrection.AffectedThePoem = true;
|
||||
dbPoem.PoemSummary = moderation.PoemSummary.Replace("ۀ", "هٔ").Replace("ك", "ک");
|
||||
dbPoem.PoemSummary = moderation.PoemSummary.Replace("ۀ", "هٔ").Replace("ك", "ک").Replace("ي", "ی");
|
||||
updatePoem = true;
|
||||
}
|
||||
}
|
||||
@ -167,7 +167,11 @@ namespace RMuseum.Services.Implementation
|
||||
if (dbVerse.VersePositionResult == CorrectionReviewResult.Approved)
|
||||
poemVerse.VersePosition = (VersePosition)dbVerse.VersePosition;
|
||||
if (dbVerse.SummaryReviewResult == CorrectionReviewResult.Approved)
|
||||
poemVerse.CoupletSummary = dbVerse.CoupletSummary;
|
||||
// dbVerse.CoupletSummary was already run through this same substitution when the
|
||||
// suggestion was first submitted (see Editor.cshtml.cs's OnPostSaveCorrectionsAsync),
|
||||
// but re-applying it here too - same as Title/PoemSummary/verse Text above - keeps
|
||||
// this field consistent even if a suggestion ever arrives through another path.
|
||||
poemVerse.CoupletSummary = dbVerse.CoupletSummary?.Replace("ۀ", "هٔ").Replace("ك", "ک").Replace("ي", "ی");
|
||||
if (dbVerse.LanguageReviewResult == CorrectionReviewResult.Approved)
|
||||
{
|
||||
if(dbVerse.LanguageId == 1)//fa-IR
|
||||
@ -910,6 +914,12 @@ namespace RMuseum.Services.Implementation
|
||||
return new Tuple<int, string>(0, $"درجهٔ اهمیت «{node.Importance}» نامعتبر است.");
|
||||
}
|
||||
|
||||
var gender = PersonGender.Unknown;
|
||||
if (!string.IsNullOrWhiteSpace(node.Gender) && !Enum.TryParse<PersonGender>(node.Gender, out gender))
|
||||
{
|
||||
return new Tuple<int, string>(0, $"جنسیت «{node.Gender}» نامعتبر است.");
|
||||
}
|
||||
|
||||
var newPerson = new GanjoorRelatedPerson()
|
||||
{
|
||||
Name = node.Name.Trim(),
|
||||
@ -923,6 +933,7 @@ namespace RMuseum.Services.Implementation
|
||||
DeathLocationId = node.DeathLocationId,
|
||||
FamilyTreeCaption = string.IsNullOrWhiteSpace(node.FamilyTreeCaption) ? null : node.FamilyTreeCaption.Trim(),
|
||||
Importance = importance,
|
||||
Gender = gender,
|
||||
MachineGenerated = false,
|
||||
};
|
||||
_context.GanjoorRelatedPersons.Add(newPerson);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user