xref: /webtrees/app/Module/RelativesTabModule.php (revision 76ab908c83a7ad14130d09d30c1d81543922dff3)
1<?php
2namespace Fisharebest\Webtrees;
3
4/**
5 * webtrees: online genealogy
6 * Copyright (C) 2015 webtrees development team
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/**
20 * Class RelativesTabModule
21 */
22class RelativesTabModule extends Module implements ModuleTabInterface {
23	/** {@inheritdoc} */
24	public function getTitle() {
25		return /* I18N: Name of a module */ I18N::translate('Families');
26	}
27
28	/** {@inheritdoc} */
29	public function getDescription() {
30		return /* I18N: Description of the “Families” module */ I18N::translate('A tab showing the close relatives of an individual.');
31	}
32
33	/** {@inheritdoc} */
34	public function defaultTabOrder() {
35		return 20;
36	}
37
38	/**
39	 * @param Date $prev
40	 * @param Date $next
41	 * @param integer $child_number
42	 *
43	 * @return string
44	 */
45	static function ageDifference(Date $prev, Date $next, $child_number = 0) {
46		if ($prev->isOK() && $next->isOK()) {
47			$days = $next->maximumJulianDay() - $prev->minimumJulianDay();
48			if ($days < 0) {
49				// Show warning triangle if dates in reverse order
50				$diff = '<i class="icon-warning"></i> ';
51			} elseif ($child_number > 1 && $days > 1 && $days < 240) {
52				// Show warning triangle if children born too close together
53				$diff = '<i class="icon-warning"></i> ';
54			} else {
55				$diff = '';
56			}
57
58			$months = round($days * 12 / 365.25); // Approximate - we do not know the calendar
59			if (abs($months) == 12 || abs($months) >= 24) {
60				$diff .= I18N::plural('%s year', '%s years', round($months / 12), I18N::number(round($months / 12)));
61			} elseif ($months != 0) {
62				$diff .= I18N::plural('%s month', '%s months', $months, I18N::number($months));
63			}
64
65			return '<div class="elderdate age">' . $diff . '</div>';
66		} else {
67			return '';
68		}
69	}
70
71	/**
72	 * @param Family $family
73	 * @param string $type
74	 * @param string $label
75	 */
76	function printFamily(Family $family, $type, $label) {
77		global $controller;
78
79		if ($family->getTree()->getPreference('SHOW_PRIVATE_RELATIONSHIPS')) {
80			$access_level = Auth::PRIV_HIDE;
81		} else {
82			$access_level = Auth::accessLevel($family->getTree());
83		}
84
85		?>
86		<table>
87			<tr>
88				<td>
89					<i class="icon-cfamily"></i>
90				</td>
91				<td>
92					<span class="subheaders"> <?php echo $label; ?> </span> -
93					<a href="<?php echo $family->getHtmlUrl(); ?>"><?php echo I18N::translate('View family'); ?></a>
94				</td>
95			</tr>
96		</table>
97		<table class="facts_table">
98		<?php
99
100		///// HUSB /////
101		$found = false;
102		foreach ($family->getFacts('HUSB', false, $access_level) as $fact) {
103			$found |= !$fact->isPendingDeletion();
104			$person = $fact->getTarget();
105			if ($person instanceof Individual) {
106				if ($fact->isPendingAddition()) {
107					$class = 'facts_label new';
108				} elseif ($fact->isPendingDeletion()) {
109					$class = 'facts_label old';
110				} else {
111					$class = 'facts_label';
112				}
113				?>
114					<tr>
115					<td class="<?php echo $class; ?>">
116						<?php echo get_close_relationship_name($controller->record, $person); ?>
117					</td>
118					<td class="<?php echo $controller->getPersonStyle($person); ?>">
119						<?php echo Theme::theme()->individualBoxLarge($person); ?>
120					</td>
121					</tr>
122				<?php
123			}
124		}
125		if (!$found && $family->canEdit()) {
126			?>
127			<tr>
128				<td class="facts_label"></td>
129				<td class="facts_value"><a href="#" onclick="return add_spouse_to_family('<?php echo $family->getXref(); ?>', 'HUSB');"><?php echo I18N::translate('Add a husband to this family'); ?></a></td>
130			</tr>
131			<?php
132		}
133
134		///// WIFE /////
135		$found = false;
136		foreach ($family->getFacts('WIFE', false, $access_level) as $fact) {
137			$person = $fact->getTarget();
138			if ($person instanceof Individual) {
139				$found |= !$fact->isPendingDeletion();
140				if ($fact->isPendingAddition()) {
141					$class = 'facts_label new';
142				} elseif ($fact->isPendingDeletion()) {
143					$class = 'facts_label old';
144				} else {
145					$class = 'facts_label';
146				}
147				?>
148				<tr>
149					<td class="<?php echo $class; ?>">
150						<?php echo get_close_relationship_name($controller->record, $person); ?>
151					</td>
152					<td class="<?php echo $controller->getPersonStyle($person); ?>">
153						<?php echo Theme::theme()->individualBoxLarge($person); ?>
154					</td>
155				</tr>
156				<?php
157			}
158		}
159		if (!$found && $family->canEdit()) {
160			?>
161			<tr>
162				<td class="facts_label"></td>
163				<td class="facts_value"><a href="#" onclick="return add_spouse_to_family('<?php echo $family->getXref(); ?>', 'WIFE');"><?php echo I18N::translate('Add a wife to this family'); ?></a></td>
164			</tr>
165			<?php
166		}
167
168		///// MARR /////
169		$found = false;
170		$prev = new Date('');
171		foreach ($family->getFacts(WT_EVENTS_MARR) as $fact) {
172			$found |= !$fact->isPendingDeletion();
173			if ($fact->isPendingAddition()) {
174				$class = ' new';
175			} elseif ($fact->isPendingDeletion()) {
176				$class = ' old';
177			} else {
178				$class = '';
179			}
180			?>
181			<tr>
182				<td class="facts_label">
183					&nbsp;
184				</td>
185				<td class="facts_value<?php echo $class; ?>">
186					<?php echo GedcomTag::getLabelValue($fact->getTag(), $fact->getDate()->display() . ' — ' . $fact->getPlace()->getFullName()); ?>
187				</td>
188			</tr>
189			<?php
190			if (!$prev->isOK() && $fact->getDate()->isOK()) {
191				$prev = $fact->getDate();
192			}
193		}
194		if (!$found && $family->canShow() && $family->canEdit()) {
195			// Add a new marriage
196			?>
197			<tr>
198				<td class="facts_label">
199					&nbsp;
200				</td>
201				<td class="facts_value">
202					<a href="#" onclick="return add_new_record('<?php echo $family->getXref(); ?>', 'MARR');">
203						<?php echo I18N::translate('Add marriage details'); ?>
204					</a>
205				</td>
206			</tr>
207			<?php
208		}
209
210		///// CHIL /////
211		$child_number = 0;
212		foreach ($family->getFacts('CHIL', false, $access_level) as $fact) {
213			$person = $fact->getTarget();
214			if ($person instanceof Individual) {
215				if ($fact->isPendingAddition()) {
216					$child_number++;
217					$class = 'facts_label new';
218				} elseif ($fact->isPendingDeletion()) {
219					$class = 'facts_label old';
220				} else {
221					$child_number++;
222					$class = 'facts_label';
223				}
224				$next = new Date('');
225				foreach ($person->getFacts(WT_EVENTS_BIRT) as $bfact) {
226					if ($bfact->getDate()->isOK()) {
227						$next = $bfact->getDate();
228						break;
229					}
230				}
231				?>
232				<tr>
233					<td class="<?php echo $class; ?>">
234						<?php echo self::ageDifference($prev, $next, $child_number); ?>
235						<?php echo get_close_relationship_name($controller->record, $person); ?>
236					</td>
237					<td class="<?php echo $controller->getPersonStyle($person); ?>">
238						<?php echo Theme::theme()->individualBoxLarge($person); ?>
239					</td>
240				</tr>
241				<?php
242				$prev = $next;
243			}
244		}
245		// Re-order children / add a new child
246		if ($family->canEdit()) {
247			if ($type == 'FAMS') {
248				$add_child_text = I18N::translate('Add a new son or daughter');
249			} else {
250				$add_child_text = I18N::translate('Add a new brother or sister');
251			}
252			?>
253			<tr>
254				<td class="facts_label">
255					<?php if (count($family->getChildren()) > 1) { ?>
256					<a href="#" onclick="reorder_children('<?php echo $family->getXref(); ?>');tabswitch(5);"><i class="icon-media-shuffle"></i> <?php echo I18N::translate('Re-order children'); ?></a>
257					<?php } ?>
258				</td>
259				<td class="facts_value">
260					<a href="#" onclick="return add_child_to_family('<?php echo $family->getXref(); ?>');"><?php echo $add_child_text; ?></a>
261					<span style='white-space:nowrap;'>
262						<a href="#" class="icon-sex_m_15x15" onclick="return add_child_to_family('<?php echo $family->getXref(); ?>','M');"></a>
263						<a href="#" class="icon-sex_f_15x15" onclick="return add_child_to_family('<?php echo $family->getXref(); ?>','F');"></a>
264					</span>
265				</td>
266			</tr>
267			<?php
268		}
269
270		echo '</table>';
271
272		return;
273	}
274
275	/** {@inheritdoc} */
276	public function getTabContent() {
277		global $WT_TREE, $show_full, $controller;
278
279		if (isset($show_full)) {
280			$saved_show_full = $show_full;
281		}
282		// We always want to see full details here
283		$show_full = 1;
284
285		ob_start();
286		?>
287		<table class="facts_table"><tr><td class="descriptionbox rela">
288		<input id="checkbox_elder" type="checkbox" onclick="jQuery('div.elderdate').toggle();" <?php echo $WT_TREE->getPreference('SHOW_AGE_DIFF') ? 'checked' : ''; ?>>
289		<label for="checkbox_elder"><?php echo I18N::translate('Show date differences'); ?></label>
290		</td></tr></table>
291		<?php
292		$families = $controller->record->getChildFamilies();
293		if (!$families && $controller->record->canEdit()) {
294			?>
295			<table class="facts_table">
296				<tr>
297					<td class="facts_value"><a href="#" onclick="return add_parent_to_individual('<?php echo $controller->record->getXref(); ?>', 'M');"><?php echo I18N::translate('Add a new father'); ?></td>
298				</tr>
299				<tr>
300					<td class="facts_value"><a href="#" onclick="return add_parent_to_individual('<?php echo $controller->record->getXref(); ?>', 'F');"><?php echo I18N::translate('Add a new mother'); ?></a></td>
301				</tr>
302			</table>
303			<?php
304		}
305
306		// parents
307		foreach ($families as $family) {
308			$this->printFamily($family, 'FAMC', $controller->record->getChildFamilyLabel($family));
309		}
310
311		// step-parents
312		foreach ($controller->record->getChildStepFamilies() as $family) {
313			$this->printFamily($family, 'FAMC', $controller->record->getStepFamilyLabel($family));
314		}
315
316		// spouses
317		$families = $controller->record->getSpouseFamilies();
318		foreach ($families as $family) {
319			$this->printFamily($family, 'FAMS', $controller->record->getSpouseFamilyLabel($family));
320		}
321
322		// step-children
323		foreach ($controller->record->getSpouseStepFamilies() as $family) {
324			$this->printFamily($family, 'FAMS', $family->getFullName());
325		}
326
327		if (!$WT_TREE->getPreference('SHOW_AGE_DIFF')) {
328			echo '<script>jQuery("DIV.elderdate").toggle();</script>';
329		}
330
331		if ($controller->record->canEdit()) {
332		?>
333		<br><table class="facts_table">
334		<?php
335			if (count($families) > 1) { ?>
336			<tr>
337				<td class="facts_value">
338				<a href="#" onclick="return reorder_families('<?php echo $controller->record->getXref(); ?>');"><?php echo I18N::translate('Re-order families'); ?></a>
339				</td>
340			</tr>
341		<?php } ?>
342			<tr>
343				<td class="facts_value">
344				<a href="#" onclick="return add_famc('<?php echo $controller->record->getXref(); ?>');"><?php echo I18N::translate('Link this individual to an existing family as a child'); ?></a>
345				</td>
346			</tr>
347			<?php if ($controller->record->getSex() != "F") { ?>
348			<tr>
349				<td class="facts_value">
350				<a href="#" onclick="return add_spouse_to_individual('<?php echo $controller->record->getXref(); ?>','WIFE');"><?php echo I18N::translate('Add a new wife'); ?></a>
351				</td>
352			</tr>
353			<tr>
354				<td class="facts_value">
355				<a href="#" onclick="return linkspouse('<?php echo $controller->record->getXref(); ?>','WIFE');"><?php echo I18N::translate('Add a wife using an existing individual'); ?></a>
356				</td>
357			</tr>
358			<?php }
359			if ($controller->record->getSex() != "M") { ?>
360			<tr>
361				<td class="facts_value">
362				<a href="#" onclick="return add_spouse_to_individual('<?php echo $controller->record->getXref(); ?>','HUSB');"><?php echo I18N::translate('Add a new husband'); ?></a>
363				</td>
364			</tr>
365			<tr>
366				<td class="facts_value">
367				<a href="#" onclick="return linkspouse('<?php echo $controller->record->getXref(); ?>','HUSB');"><?php echo I18N::translate('Add a husband using an existing individual'); ?></a>
368				</td>
369			</tr>
370			<?php } ?>
371			<tr>
372				<td class="facts_value">
373				<a href="#" onclick="return add_child_to_individual('<?php echo $controller->record->getXref(); ?>','U');"><?php echo I18N::translate('Add a child to create a one-parent family'); ?></a>
374				</td>
375			</tr>
376		</table>
377		<?php } ?>
378		<br>
379		<?php
380
381		unset($show_full);
382		if (isset($saved_show_full)) {
383			$show_full = $saved_show_full;
384		}
385
386		return '<div id="' . $this->getName() . '_content">' . ob_get_clean() . '</div>';
387	}
388
389	/** {@inheritdoc} */
390	public function hasTabContent() {
391		return true;
392	}
393	/** {@inheritdoc} */
394	public function isGrayedOut() {
395		return false;
396	}
397	/** {@inheritdoc} */
398	public function canLoadAjax() {
399		return !Auth::isSearchEngine(); // Search engines cannot use AJAX
400	}
401
402	/** {@inheritdoc} */
403	public function getPreLoadContent() {
404		return '';
405	}
406}
407