.
*/
namespace Fisharebest\Webtrees\Controller;
use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\Database;
use Fisharebest\Webtrees\Fact;
use Fisharebest\Webtrees\Family;
use Fisharebest\Webtrees\Filter;
use Fisharebest\Webtrees\Functions\FunctionsPrint;
use Fisharebest\Webtrees\Functions\FunctionsPrintFacts;
use Fisharebest\Webtrees\GedcomCode\GedcomCodeName;
use Fisharebest\Webtrees\GedcomTag;
use Fisharebest\Webtrees\I18N;
use Fisharebest\Webtrees\Individual;
use Fisharebest\Webtrees\Menu;
use Fisharebest\Webtrees\Module;
use Fisharebest\Webtrees\User;
/**
* 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;
/** ModuleTabInterface[] List of tabs to show */
public $tabs;
/**
* 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());
$this->tabs = Module::getActiveTabs($this->record->getTree());
}
}
/**
* 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();
}
/**
* Handle AJAX requests - to generate the tab content
*/
public function ajaxRequest() {
// Search engines should not make AJAX requests
if (Auth::isSearchEngine()) {
http_response_code(403);
exit;
}
// Initialise tabs
$tab = Filter::get('module');
// A request for a non-existant tab?
if (array_key_exists($tab, $this->tabs)) {
$mod = $this->tabs[$tab];
} else {
http_response_code(404);
exit;
}
header("Content-Type: text/html; charset=UTF-8"); // AJAX calls do not have the meta tag headers and need this set
header("X-Robots-Tag: noindex,follow"); // AJAX pages should not show up in search results, any links can be followed though
echo $mod->getTabContent();
if (WT_DEBUG_SQL) {
echo Database::getQueryLog();
}
}
/**
* print information for a name record
*
* @param Fact $event the event object
*/
public function printNameRecord(Fact $event) {
$factrec = $event->getGedcom();
// Create a dummy record, so we can extract the formatted NAME value from the event.
$dummy = new Individual(
'xref',
"0 @xref@ INDI\n1 DEAT Y\n" . $factrec,
null,
$event->getParent()->getTree()
);
$all_names = $dummy->getAllNames();
$primary_name = $all_names[0];
$this->name_count++;
if ($this->name_count > 1) { echo '
', $dummy->getFullName(), '
'; } // Other names accordion element
echo '';
echo '
';
echo '
- ', I18N::translate('Name'), '
';
$dummy->setPrimaryName(0);
echo '- ', $dummy->getFullName();
if ($this->name_count == 1) {
if (Auth::isAdmin()) {
$user = User::findByGenealogyRecord($this->record);
if ($user) {
echo ' - ' . Filter::escapeHtml($user->getUserName()) . '';
}
}
}
if ($this->record->canEdit() && !$event->isPendingDeletion()) {
echo "";
echo "";
}
echo '
';
echo '
';
echo '
';
$ct = preg_match_all('/\n2 (\w+) (.*)/', $factrec, $nmatch, PREG_SET_ORDER);
for ($i = 0; $i < $ct; $i++) {
echo '
';
$fact = $nmatch[$i][1];
if ($fact != 'SOUR' && $fact != 'NOTE' && $fact != 'SPFX') {
echo '
- ', GedcomTag::getLabel($fact, $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 = Filter::escapeHtml($nmatch[$i][2]);
$name = str_replace('/', '', $name);
$name = preg_replace('/(\S*)\*/', '\\1', $name);
switch ($fact) {
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 = Filter::escapeHtml($primary_name['surname']);
if (strpos($primary_name['surname'], str_replace(',', ' ', $nmatch[$i][2])) !== false) {
echo '' . $surname . '';
} else {
echo I18N::translate('%1$s (%2$s)', '' . $surname . '', '' . $name . '');
}
break;
default:
echo '' . $name . '';
break;
}
}
echo '
';
echo '
';
}
echo '
';
}
if (preg_match("/\n2 SOUR/", $factrec)) {
echo '
', FunctionsPrintFacts::printFactSources($factrec, 2), '
';
}
if (preg_match("/\n2 NOTE/", $factrec)) {
echo '
', FunctionsPrint::printFactNotes($factrec, 2), '
';
}
echo '
';
}
/**
* print information for a sex record
*
* @param Fact $event the Event object
*/
public function printSexRecord(Fact $event) {
$sex = $event->getValue();
if (empty($sex)) {
$sex = 'U';
}
echo 'canEdit()) {
echo ' title="', I18N::translate('Male'), ' - ', I18N::translate('Edit'), '"';
echo ' onclick="edit_record(\'' . $this->record->getXref() . '\', \'' . $event->getFactId() . '\'); return false;">';
} else {
echo ' title="', I18N::translate('Male'), '">';
}
break;
case 'F':
echo 'female_gender"';
if ($event->canEdit()) {
echo ' title="', I18N::translate('Female'), ' - ', I18N::translate('Edit'), '"';
echo ' onclick="edit_record(\'' . $this->record->getXref() . '\', \'' . $event->getFactId() . '\'); return false;">';
} else {
echo ' title="', I18N::translate('Female'), '">';
}
break;
default:
echo 'unknown_gender"';
if ($event->canEdit()) {
echo ' title="', I18N::translateContext('unknown gender', 'Unknown'), ' - ', I18N::translate('Edit'), '"';
echo ' onclick="edit_record(\'' . $this->record->getXref() . '\', \'' . $event->getFactId() . '\'); return false;">';
} else {
echo ' title="', I18N::translateContext('unknown gender', 'Unknown'), '">';
}
break;
}
echo '';
}
/**
* 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())) {
$menu->addSubmenu(new Menu(I18N::translate('Add a name'), '#', 'menu-indi-addname', array(
'onclick' => 'return add_name("' . $this->record->getXref() . '");',
)));
$has_sex_record = false;
foreach ($this->record->getFacts() as $fact) {
if ($fact->getTag() === 'SEX' && $fact->canEdit()) {
$menu->addSubmenu(new Menu(I18N::translate('Edit the gender'), '#', 'menu-indi-editsex', array(
'onclick' => 'return edit_record("' . $this->record->getXref() . '", "' . $fact->getFactId() . '");',
)));
$has_sex_record = true;
break;
}
}
if (!$has_sex_record) {
$menu->addSubmenu(new Menu(I18N::translate('Edit the gender'), '#', 'menu-indi-editsex', array(
'onclick' => 'return add_new_record("' . $this->record->getXref() . '", "SEX");',
)));
}
if (count($this->record->getSpouseFamilies()) > 1) {
$menu->addSubmenu(new Menu(I18N::translate('Re-order families'), '#', 'menu-indi-orderfam', array(
'onclick' => 'return reorder_families("' . $this->record->getXref() . '");',
)));
}
// delete
$menu->addSubmenu(new Menu(I18N::translate('Delete'), '#', 'menu-indi-del', array(
'onclick' => 'return delete_record("' . I18N::translate('Are you sure you want to delete ā%sā?', Filter::escapeJs(Filter::unescapeHtml($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'), '#', 'menu-indi-editraw', array(
'onclick' => 'return edit_raw("' . $this->record->getXref() . '");',
)));
}
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() {
global $controller;
$html = '';
$active = 0;
$n = 0;
foreach (Module::getActiveSidebars($this->record->getTree()) as $mod) {
if ($mod->hasSidebarContent()) {
$html .= '';
$html .= '' . $mod->getSidebarContent() . '
';
// The family navigator should be opened by default
if ($mod->getName() == 'family_nav') {
$active = $n;
}
++$n;
}
}
if ($html) {
$controller
->addInlineJavascript('
jQuery("#sidebarAccordion").accordion({
active:' . $active . ',
heightStyle: "content",
collapsible: true,
});
');
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();
}
}
}