xref: /webtrees/app/Module/FamilyNavigatorModule.php (revision 3cf92ae205660ec36316541b9e23f2ecbf0af8bb)
1<?php
2/**
3 * webtrees: online genealogy
4 * Copyright (C) 2015 webtrees development team
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16namespace Fisharebest\Webtrees\Module;
17
18use Fisharebest\Webtrees\Auth;
19use Fisharebest\Webtrees\Family;
20use Fisharebest\Webtrees\Functions\Functions;
21use Fisharebest\Webtrees\I18N;
22use Fisharebest\Webtrees\Individual;
23use Fisharebest\Webtrees\Menu;
24
25/**
26 * Class FamilyNavigatorModule
27 */
28class FamilyNavigatorModule extends AbstractModule implements ModuleSidebarInterface {
29	const TTL = "<div class='flyout2'>%s</div>";
30	const LNK = "<div class='flyout3' data-href='%s'>%s</div>";
31	const MSG = "<div class='flyout4'>(%s)</div>"; // class flyout4 not used in standard themes
32
33	/** {@inheritdoc} */
34	public function getTitle() {
35		return /* I18N: Name of a module/sidebar */ I18N::translate('Family navigator');
36	}
37
38	/** {@inheritdoc} */
39	public function getDescription() {
40		return /* I18N: Description of the “Family navigator” module */ I18N::translate('A sidebar showing an individual’s close families and relatives.');
41	}
42
43	/** {@inheritdoc} */
44	public function defaultSidebarOrder() {
45		return 20;
46	}
47
48	/** {@inheritdoc} */
49	public function hasSidebarContent() {
50		return !Auth::isSearchEngine();
51	}
52
53	/** {@inheritdoc} */
54	public function getSidebarAjaxContent() {
55		return '';
56	}
57
58	/**
59	 * Load this sidebar synchronously.
60	 *
61	 * @return string
62	 */
63	public function getSidebarContent() {
64		global $controller;
65
66		$controller->addInlineJavascript('
67			jQuery("#sb_family_nav_content")
68				.on("click", ".flyout a", function() {
69					return false;
70				})
71				.on("click", ".flyout3", function() {
72					window.location.href = jQuery(this).data("href");
73					return false;
74				});
75		');
76
77		ob_start();
78
79		?>
80		<div id="sb_family_nav_content">
81			<table class="nav_content">
82
83		<?php
84		//-- parent families -------------------------------------------------------------
85		foreach ($controller->record->getChildFamilies() as $family) {
86			$this->drawFamily($family, $controller->record->getChildFamilyLabel($family));
87		}
88		//-- step parents ----------------------------------------------------------------
89		foreach ($controller->record->getChildStepFamilies() as $family) {
90			$this->drawFamily($family, $controller->record->getStepFamilyLabel($family));
91		}
92		//-- spouse and children --------------------------------------------------
93		foreach ($controller->record->getSpouseFamilies() as $family) {
94			$this->drawFamily($family, $controller->getSpouseFamilyLabel($family, $controller->record));
95		}
96		//-- step children ----------------------------------------------------------------
97		foreach ($controller->record->getSpouseStepFamilies() as $family) {
98			$this->drawFamily($family, $family->getFullName());
99		}
100		?>
101			</table>
102		</div>
103		<?php
104
105		return ob_get_clean();
106	}
107
108	/**
109	 * Format a family.
110	 *
111	 * @param Family $family
112	 * @param string $title
113	 */
114	private function drawFamily(Family $family, $title) {
115		global $controller;
116
117		?>
118		<tr>
119			<td class="center" colspan="2">
120				<a class="famnav_title" href="<?php echo $family->getHtmlUrl(); ?>">
121					<?php echo $title; ?>
122				</a>
123			</td>
124		</tr>
125		<?php
126		foreach ($family->getSpouses() as $spouse) {
127			$menu = new Menu(Functions::getCloseRelationshipName($controller->record, $spouse));
128			$menu->addClass('', 'submenu flyout');
129			$menu->addSubmenu(new Menu($this->getParents($spouse)));
130			?>
131			<tr>
132				<td class="facts_label">
133					<?php echo $menu->getMenu(); ?>
134				</td>
135				<td class="center <?php echo $controller->getPersonStyle($spouse); ?> nam">
136					<a class="famnav_link" href="<?php echo $spouse->getHtmlUrl(); ?>">
137						<?php echo $spouse->getFullName(); ?>
138					</a>
139					<div class="font9">
140						<?php echo $spouse->getLifeSpan(); ?>
141					</div>
142				</td>
143			</tr>
144		<?php
145		}
146
147		foreach ($family->getChildren() as $child) {
148			$menu = new Menu(Functions::getCloseRelationshipName($controller->record, $child));
149			$menu->addClass('', 'submenu flyout');
150			$menu->addSubmenu(new Menu($this->getFamily($child)));
151			?>
152			<tr>
153				<td class="facts_label">
154					<?php echo $menu->getMenu(); ?>
155				</td>
156				<td class="center <?php echo $controller->getPersonStyle($child); ?> nam">
157					<a class="famnav_link" href="<?php echo $child->getHtmlUrl(); ?>">
158						<?php echo $child->getFullName(); ?>
159					</a>
160					<div class="font9">
161						<?php echo $child->getLifeSpan(); ?>
162					</div>
163				</td>
164			</tr>
165		<?php
166		}
167	}
168
169	/**
170	 * Format an individual.
171	 *
172	 * @param      $person
173	 * @param bool $showUnknown
174	 *
175	 * @return string
176	 */
177	private function getHTML($person, $showUnknown = false) {
178		if ($person instanceof Individual) {
179			return sprintf(self::LNK, $person->getHtmlUrl(), $person->getFullName());
180		} elseif ($showUnknown) {
181			return sprintf(self::MSG, I18N::translate('unknown'));
182		} else {
183			return '';
184		}
185	}
186
187	/**
188	 * Forat the parents of an individual.
189	 *
190	 * @param Individual $person
191	 *
192	 * @return string
193	 */
194	private function getParents(Individual $person) {
195		$father = null;
196		$mother = null;
197		$html   = sprintf(self::TTL, I18N::translate('Parents'));
198		$family = $person->getPrimaryChildFamily();
199		if (!Auth::isSearchEngine() && $person->canShowName() && $family !== null) {
200			$father = $family->getHusband();
201			$mother = $family->getWife();
202			$html .= $this->getHTML($father) .
203					 $this->getHTML($mother);
204
205			// Can only have a step parent if one & only one parent found at this point
206			if ($father instanceof Individual xor $mother instanceof Individual) {
207				$stepParents = '';
208				foreach ($person->getChildStepFamilies() as $family) {
209					if (!$father instanceof Individual) {
210						$stepParents .= $this->getHTML($family->getHusband());
211					} else {
212						$stepParents .= $this->getHTML($family->getWife());
213					}
214				}
215				if ($stepParents) {
216					$relationship = $father instanceof Individual ?
217						I18N::translateContext("father’s wife", "step-mother") : I18N::translateContext("mother’s husband", "step-father");
218					$html .= sprintf(self::TTL, $relationship) . $stepParents;
219				}
220			}
221		}
222		if (!($father instanceof Individual || $mother instanceof Individual)) {
223			$html .= sprintf(self::MSG, I18N::translateContext('unknown family', 'unknown'));
224		}
225
226		return $html;
227	}
228
229	/**
230	 * Format a family.
231	 *
232	 * @param Individual $person
233	 *
234	 * @return string
235	 */
236	private function getFamily(Individual $person) {
237		$html = '';
238		if ($person->canShowName() && !Auth::isSearchEngine()) {
239			foreach ($person->getSpouseFamilies() as $family) {
240				$spouse = $family->getSpouse($person);
241				$html .= $this->getHTML($spouse, true);
242				$children = $family->getChildren();
243				if (count($children) > 0) {
244					$html .= "<ul class='clist'>";
245					foreach ($children as $child) {
246						$html .= '<li>' . $this->getHTML($child) . '</li>';
247					}
248					$html .= '</ul>';
249				}
250			}
251		}
252		if (!$html) {
253			$html = sprintf(self::MSG, I18N::translate('none'));
254		}
255
256		return sprintf(self::TTL, I18N::translate('Family')) . $html;
257	}
258
259}
260