.
*/
namespace Fisharebest\Webtrees\Controller;
use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Fact;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
use Fisharebest\Webtrees\FontAwesome;
use Fisharebest\Webtrees\Functions\FunctionsPrint;
use Fisharebest\Webtrees\Functions\FunctionsPrintFacts;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeName;
use Fisharebest\Webtrees\GedcomTag;
use Fisharebest\Webtrees\Html;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Menu;
use Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\Module\ModuleTabInterface;
/**
* Controller for the individual page
*/
class IndividualController extends GedcomRecordController {
/** @var int Count of names */
public $name_count = 0;
/** @var int Count of names. */
public $total_names = 0;
/**
* Startup activity
*
* @param Individual|null $record
*/
public function __construct($record) {
parent::__construct($record);
// If we can display the details, add them to the page header
if ($this->record && $this->record->canShow()) {
$this->setPageTitle($this->record->getFullName() . ' ' . $this->record->getLifeSpan());
}
}
/**
* Get significant information from this page, to allow other pages such as
* charts and reports to initialise with the same records
*
* @return Individual
*/
public function getSignificantIndividual() {
if ($this->record) {
return $this->record;
}
return parent::getSignificantIndividual();
}
/**
* Get significant information from this page, to allow other pages such as
* charts and reports to initialise with the same records
*
* @return Family
*/
public function getSignificantFamily() {
if ($this->record) {
foreach ($this->record->getChildFamilies() as $family) {
return $family;
}
foreach ($this->record->getSpouseFamilies() as $family) {
return $family;
}
}
return parent::getSignificantFamily();
}
/**
* Which tabs should we show on this individual's page.
* We don't show empty tabs.
*
* @return ModuleTabInterface[]
*/
public function getTabs() {
$active_tabs = Module::getActiveTabs($this->record->getTree());
return array_filter($active_tabs, function(ModuleTabInterface $tab) { return $tab->hasTabContent(); });
}
/**
* Handle AJAX requests - to generate the tab content
*/
public function ajaxRequest() {
header('Content-Type: text/html; charset=UTF-8');
$tab = Filter::get('module');
$tabs = $this->getTabs();
if (!array_key_exists($tab, $tabs)) {
http_response_code(404);
} else {
echo $tabs[$tab]->getTabContent();
}
}
/**
* Format a name record
*
* @param int $n
* @param Fact $fact
*
* @return string
*/
public function formatNameRecord($n, Fact $fact) {
$individual = $fact->getParent();
// Create a dummy record, so we can extract the formatted NAME value from it.
$dummy = new Individual(
'xref',
"0 @xref@ INDI\n1 DEAT Y\n" . $fact->getGedcom(),
null,
$individual->getTree()
);
$dummy->setPrimaryName(0); // Make sure we use the name from "1 NAME"
$container_class = 'card';
$content_class = 'collapse';
$aria = 'false';
if ($n === 0) {
$content_class = 'collapse show';
$aria = 'true';
}
if ($fact->isPendingDeletion()) {
$container_class .= ' old';
} elseif ($fact->isPendingAddition()) {
$container_class .= ' new';
}
ob_start();
echo '
- ', I18N::translate('Name'), '
';
echo '- ', $dummy->getFullName(), '
';
$ct = preg_match_all('/\n2 (\w+) (.*)/', $fact->getGedcom(), $nmatch, PREG_SET_ORDER);
for ($i = 0; $i < $ct; $i++) {
$tag = $nmatch[$i][1];
if ($tag != 'SOUR' && $tag != 'NOTE' && $tag != 'SPFX') {
echo '- ', GedcomTag::getLabel($tag, $this->record), '
';
echo '- '; // Before using dir="auto" on this field, note that Gecko treats this as an inline element but WebKit treats it as a block element
if (isset($nmatch[$i][2])) {
$name = Html::escape($nmatch[$i][2]);
$name = str_replace('/', '', $name);
$name = preg_replace('/(\S*)\*/', '\\1', $name);
switch ($tag) {
case 'TYPE':
echo GedcomCodeName::getValue($name, $this->record);
break;
case 'SURN':
// The SURN field is not necessarily the surname.
// Where it is not a substring of the real surname, show it after the real surname.
$surname = Html::escape($dummy->getAllNames()[0]['surname']);
$surns = preg_replace('/, */', ' ', $nmatch[$i][2]);
if (strpos($dummy->getAllNames()[0]['surname'], $surns) !== false) {
echo '' . $surname . '';
} else {
echo I18N::translate('%1$s (%2$s)', '' . $surname . '', '' . $name . '');
}
break;
default:
echo '' . $name . '';
break;
}
}
echo '
';
echo '
';
}
}
if (preg_match("/\n2 SOUR/", $fact->getGedcom())) {
echo '', FunctionsPrintFacts::printFactSources($fact->getGedcom(), 2), '
';
}
if (preg_match("/\n2 NOTE/", $fact->getGedcom())) {
echo '', FunctionsPrint::printFactNotes($fact->getGedcom(), 2), '
';
}
$content = ob_get_clean();
if ($this->record->canEdit() && !$fact->isPendingDeletion()) {
$edit_links =
FontAwesome::linkIcon('delete', I18N::translate('Delete this name'), ['class' => 'btn btn-link', 'href' => '#', 'onclick' => 'return delete_fact("' . I18N::translate('Are you sure you want to delete this fact?') . '", "' . $this->record->getXref() . '", "' . $fact->getFactId() . '");']) .
FontAwesome::linkIcon('edit', I18N::translate('Edit the name'), ['class' => 'btn btn-link', 'href' => 'edit_interface.php?action=editname&xref=' . $this->record->getXref() . '&fact_id=' . $fact->getFactId() . '&ged=' . $this->record->getTree()->getNameHtml()]);
} else {
$edit_links = '';
}
return '
';
}
/**
* print information for a sex record
*
* @param Fact $fact
*
* @return string
*/
public function formatSexRecord(Fact $fact) {
$individual = $fact->getParent();
switch ($fact->getValue()) {
case 'M':
$sex = I18N::translate('Male');
break;
case 'F':
$sex = I18N::translate('Female');
break;
default:
$sex = I18N::translateContext('unknown gender', 'Unknown');
break;
}
$container_class = 'card';
if ($fact->isPendingDeletion()) {
$container_class .= ' old';
} elseif ($fact->isPendingAddition()) {
$container_class .= ' new';
}
if ($individual->canEdit() && !$fact->isPendingDeletion()) {
$edit_links = FontAwesome::linkIcon('edit', I18N::translate('Edit the gender'), ['class' => 'btn btn-link', 'href' => 'edit_interface.php?action=edit&xref=' . $individual->getXref() . '&fact_id=' . $fact->getFactId() . '&ged=' . $individual->getTree()->getNameHtml() ]);
} else {
$edit_links = '';
}
return '
';
}
/**
* get edit menu
*/
public function getEditMenu() {
if (!$this->record || $this->record->isPendingDeletion()) {
return null;
}
// edit menu
$menu = new Menu(I18N::translate('Edit'), '#', 'menu-indi');
if (Auth::isEditor($this->record->getTree())) {
// delete
$menu->addSubmenu(new Menu(I18N::translate('Delete'), '#', 'menu-indi-del', [
'onclick' => 'return delete_record("' . I18N::translate('Are you sure you want to delete ā%sā?', strip_tags($this->record->getFullName())) . '", "' . $this->record->getXref() . '");',
]));
}
// edit raw
if (Auth::isAdmin() || Auth::isEditor($this->record->getTree()) && $this->record->getTree()->getPreference('SHOW_GEDCOM_RECORD')) {
$menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), 'edit_interface.php?action=editraw&ged=' . $this->record->getTree()->getNameHtml() . '&xref=' . $this->record->getXref(), 'menu-indi-editraw'));
}
return $menu;
}
/**
* get the person box stylesheet class for the given person
*
* @param Individual $person
*
* @return string returns 'person_box', 'person_boxF', or 'person_boxNN'
*/
public function getPersonStyle($person) {
switch ($person->getSex()) {
case 'M':
$class = 'person_box';
break;
case 'F':
$class = 'person_boxF';
break;
default:
$class = 'person_boxNN';
break;
}
if ($person->isPendingDeletion()) {
$class .= ' old';
} elseif ($person->isPendingAddtion()) {
$class .= ' new';
}
return $class;
}
/**
* Get significant information from this page, to allow other pages such as
* charts and reports to initialise with the same records
*
* @return string
*/
public function getSignificantSurname() {
if ($this->record) {
list($surn) = explode(',', $this->record->getSortName());
return $surn;
} else {
return '';
}
}
/**
* Get the contents of sidebar.
*
* @return string
*/
public function getSideBarContent() {
$html = '';
foreach (Module::getActiveSidebars($this->record->getTree()) as $module) {
if ($module->hasSidebarContent()) {
$class = $module->getName() === 'family_nav' ? 'collapse show' : 'collapse';
$aria = $module->getName() === 'family_nav' ? 'true' : 'false';
$html .= '
';
}
}
if ($html) {
return '';
} else {
return '';
}
}
/**
* Get the description for the family.
*
* For example, "XXX's family with new wife".
*
* @param Family $family
* @param Individual $individual
*
* @return string
*/
public function getSpouseFamilyLabel(Family $family, Individual $individual) {
$spouse = $family->getSpouse($individual);
if ($spouse) {
return
/* I18N: %s is the spouse name */
I18N::translate('Family with %s', $spouse->getFullName());
} else {
return $family->getFullName();
}
}
}