divan/DivanRazor/wwwroot/js/personwindow.js
Anas Rashid 532d005cdb Rename Ganjoor -> Divan throughout the code
Projects (GanjooRazor -> DivanRazor, GanjoorService.sln -> DivanService.sln), files,
folders, classes, namespaces, settings, API routes (/api/divan) and DB tables (Divan*).
External addresses (ganjoor.net, github.com/ganjoor) unchanged. Migrations renamed
consistently (no pending model changes); requires a fresh database.
Upstream RUNNING_LOCALLY/SEMANTIC_SEARCH docs archived unmodified under docs/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 23:49:01 +02:00

140 lines
6.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Generic inline-modal shell, loaded on every page (see _Layout.cshtml / _AdminLayout.cshtml),
// used to replace what used to be four standalone pages: Person.cshtml (a person's profile),
// People.cshtml (family-tree-roots index), PeopleGraph.cshtml (whole-site relationship graph) and
// FamilyTree.cshtml (one person's family-tree chart). Those pages had no independent purpose of
// their own - they only ever existed to show data reachable from somewhere else (a poem's tagged
// persons, a category's "شخصیت‌ها" tab, an admin moderation queue) - so instead of navigating
// away, callers open one of these three windows over whatever page they're already on:
//
// PersonWindow.open(id) - a small modal: one person's bio/relations/affiliations/poems,
// fetched from /PersonWindow/{id} (Person.cshtml's old content,
// stripped of site chrome - see PersonWindow.cshtml).
// PeopleExplorer.open() - a large modal: the whole-site force-directed graph (formerly
// /PeopleGraph) plus the family-tree-roots list (formerly /People),
// merged into one fragment fetched from /PeopleExplorer.
// FamilyTreeWindow.open(id) - a large modal: one person's connected-kinship-component tree
// chart (formerly /FamilyTree/{id}), fetched from
// /FamilyTreeWindow/{id} - see FamilyTreeWindow.cshtml.
//
// All three render into the same reusable overlay/modal shell built here on first use.
(function () {
'use strict';
var STYLE_ID = 'up-modal-styles';
var overlay, modal, body, closeBtn;
function ensureStyles() {
if (document.getElementById(STYLE_ID)) return;
var style = document.createElement('style');
style.id = STYLE_ID;
style.textContent =
'.up-modal-overlay{position:fixed;inset:0;background:rgba(30,20,10,.55);z-index:9000;' +
'display:none;align-items:flex-start;justify-content:center;overflow-y:auto;padding:5vh 16px;}' +
'.up-modal-overlay--open{display:flex;}' +
'.up-modal{position:relative;background:#fffdf7;border-radius:10px;box-shadow:0 8px 30px rgba(0,0,0,.35);' +
'padding:20px 24px;max-width:640px;width:100%;max-height:90vh;overflow-y:auto;direction:rtl;text-align:right;}' +
'.up-modal--lg{max-width:900px;}' +
'.up-modal-close{position:absolute;left:12px;top:10px;border:none;background:none;font-size:22px;' +
'line-height:1;cursor:pointer;color:#7a4a2a;}' +
'.up-modal-loading{text-align:center;padding:30px 0;}' +
'body.up-modal-noscroll{overflow:hidden;}';
document.head.appendChild(style);
}
function ensureShell() {
if (overlay) return;
ensureStyles();
overlay = document.createElement('div');
overlay.id = 'up-modal-overlay';
overlay.className = 'up-modal-overlay';
overlay.innerHTML =
'<div class="up-modal" id="up-modal">' +
'<button type="button" class="up-modal-close" id="up-modal-close" aria-label="بستن">×</button>' +
'<div class="up-modal-body" id="up-modal-body"></div>' +
'</div>';
document.body.appendChild(overlay);
modal = document.getElementById('up-modal');
body = document.getElementById('up-modal-body');
closeBtn = document.getElementById('up-modal-close');
closeBtn.addEventListener('click', closeModal);
overlay.addEventListener('click', function (evt) {
if (evt.target === overlay) closeModal();
});
document.addEventListener('keydown', function (evt) {
if (evt.key === 'Escape' && overlay.classList.contains('up-modal-overlay--open')) {
closeModal();
}
});
}
function openModal(large) {
ensureShell();
modal.classList.toggle('up-modal--lg', !!large);
body.innerHTML = '<div class="up-modal-loading"><img src="/image/loading.gif" alt="بارگذاری" /></div>';
overlay.classList.add('up-modal-overlay--open');
document.body.classList.add('up-modal-noscroll');
}
function closeModal() {
if (!overlay) return;
overlay.classList.remove('up-modal-overlay--open');
document.body.classList.remove('up-modal-noscroll');
}
function loadInto(url, onReady) {
$.ajax({
type: 'GET',
url: url,
error: function () {
if (body) body.innerHTML = '<p>خطا در بارگذاری اطلاعات.</p>';
},
success: function (data) {
body.innerHTML = data;
if (onReady) onReady();
}
});
}
function openPerson(id) {
openModal(false);
loadInto('/PersonWindow/' + String(id));
}
function openExplorer() {
openModal(true);
loadInto('/PeopleExplorer', function () {
var dataEl = document.getElementById('pge-data');
if (dataEl && window.DivanPeopleGraph) {
var graphData = JSON.parse(dataEl.textContent);
DivanPeopleGraph.render({
containerId: 'pge-container',
svgId: 'pge-svg',
tableBodyId: 'pge-table-body',
legendId: 'pge-legend',
searchInputId: 'pge-search',
resetButtonId: 'pge-reset',
data: graphData
});
}
});
}
function openFamilyTree(id) {
openModal(true);
loadInto('/FamilyTreeWindow/' + String(id), function () {
var dataEl = document.getElementById('ftw-data');
var rootIdEl = document.getElementById('ftw-root-id');
if (dataEl && rootIdEl && window.DivanFamilyTree) {
var treeData = JSON.parse(dataEl.textContent);
var rootId = parseInt(rootIdEl.value, 10);
DivanFamilyTree.render('familytree-container', 'familytree-svg', 'familytree-tooltip', treeData, rootId);
}
});
}
window.PersonWindow = { open: openPerson, close: closeModal };
window.PeopleExplorer = { open: openExplorer, close: closeModal };
window.FamilyTreeWindow = { open: openFamilyTree, close: closeModal };
})();