xref: /webtrees/app/Module/FamilyNavigatorModule.php (revision 268bcb455673155e78b9762911cd30906516f97b)
1<?php
2namespace Fisharebest\Webtrees\Module;
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 */
18use Fisharebest\Webtrees\Auth;
19use Fisharebest\Webtrees\Family;
20use Fisharebest\Webtrees\I18N;
21use Fisharebest\Webtrees\Individual;
22use Fisharebest\Webtrees\Menu;
23
24/**
25 * Class FamilyNavigatorModule
26 */
27class FamilyNavigatorModule extends AbstractModule implements ModuleSidebarInterface {
28	const TTL = "<div class='flyout2'>%s</div>";
29	const LNK = "<div class='flyout3' data-href='%s'>%s</div>";
30	const MSG = "<div class='flyout4'>(%s)</div>"; // class flyout4 not used in standard themes
31
32	/** {@inheritdoc} */
33	public function getTitle() {
34		return /* I18N: Name of a module/sidebar */ I18N::translate('Family navigator');
35	}
36
37	/** {@inheritdoc} */
38	public function getDescription() {
39		return /* I18N: Description of the “Family navigator” module */ I18N::translate('A sidebar showing an individual’s close families and relatives.');
40	}
41
42	/** {@inheritdoc} */
43	public function defaultSidebarOrder() {
44		return 20;
45	}
46
47	/** {@inheritdoc} */
48	public function hasSidebarContent() {
49		return !Auth::isSearchEngine();
50	}
51
52	/** {@inheritdoc} */
53	public function getSidebarAjaxContent() {
54		return '';
55	}
56
57	/** {@inheritdoc} */
58	public function getSidebarContent() {
59		global $controller;
60
61		$controller->addInlineJavascript('
62			jQuery("#sb_family_nav_content")
63				.on("click", ".flyout a", function() {
64					return false;
65				})
66				.on("click", ".flyout3", function() {
67					window.location.href = jQuery(this).data("href");
68					return false;
69				});
70		');
71
72		ob_start();
73
74		?>
75		<div id="sb_family_nav_content">
76			<table class="nav_content">
77
78		<?php
79		//-- parent families -------------------------------------------------------------
80		foreach ($controller->record->getChildFamilies() as $family) {
81			$this->drawFamily($family, $controller->record->getChildFamilyLabel($family));
82		}
83		//-- step parents ----------------------------------------------------------------
84		foreach ($controller->record->getChildStepFamilies() as $family) {
85			$this->drawFamily($family, $controller->record->getStepFamilyLabel($family));
86		}
87		//-- spouse and children --------------------------------------------------
88		foreach ($controller->record->getSpouseFamilies() as $family) {
89			$this->drawFamily($family, $controller->getSpouseFamilyLabel($family, $controller->record));
90		}
91		//-- step children ----------------------------------------------------------------
92		foreach ($controller->record->getSpouseStepFamilies() as $family) {
93			$this->drawFamily($family, $family->getFullName());
94		}
95		?>
96			</table>
97		</div>
98		<?php
99
100		return ob_get_clean();
101	}
102
103	/**
104	 * @param Family $family
105	 * @param string $title
106	 */
107	private function drawFamily(Family $family, $title) {
108		global $controller;
109
110		?>
111		<tr>
112			<td class="center" colspan="2">
113				<a class="famnav_title" href="<?php echo $family->getHtmlUrl(); ?>">
114					<?php echo $title; ?>
115				</a>
116			</td>
117		</tr>
118		<?php
119		foreach ($family->getSpouses() as $spouse) {
120			$menu = new Menu(get_close_relationship_name($controller->record, $spouse));
121			$menu->addClass('', 'submenu flyout');
122			$menu->addSubmenu(new Menu($this->getParents($spouse)));
123			?>
124			<tr>
125				<td class="facts_label">
126					<?php echo $menu->getMenu(); ?>
127				</td>
128				<td class="center <?php echo $controller->getPersonStyle($spouse); ?> nam">
129					<a class="famnav_link" href="<?php echo $spouse->getHtmlUrl(); ?>">
130						<?php echo $spouse->getFullName(); ?>
131					</a>
132					<div class="font9">
133						<?php echo $spouse->getLifeSpan(); ?>
134					</div>
135				</td>
136			</tr>
137		<?php
138		}
139
140		foreach ($family->getChildren() as $child) {
141			$menu = new Menu(get_close_relationship_name($controller->record, $child));
142			$menu->addClass('', 'submenu flyout');
143			$menu->addSubmenu(new Menu($this->getFamily($child)));
144			?>
145			<tr>
146				<td class="facts_label">
147					<?php echo $menu->getMenu(); ?>
148				</td>
149				<td class="center <?php echo $controller->getPersonStyle($child); ?> nam">
150					<a class="famnav_link" href="<?php echo $child->getHtmlUrl(); ?>">
151						<?php echo $child->getFullName(); ?>
152					</a>
153					<div class="font9">
154						<?php echo $child->getLifeSpan(); ?>
155					</div>
156				</td>
157			</tr>
158		<?php
159		}
160	}
161
162	/**
163	 * @param      $person
164	 * @param bool $showUnknown
165	 *
166	 * @return string
167	 */
168	private function getHTML($person, $showUnknown = false) {
169		if ($person instanceof Individual) {
170			return sprintf(self::LNK, $person->getHtmlUrl(), $person->getFullName());
171		} elseif ($showUnknown) {
172			return sprintf(self::MSG, I18N::translate('unknown'));
173		} else {
174			return '';
175		}
176	}
177
178	/**
179	 * @param Individual $person
180	 *
181	 * @return string
182	 */
183	private function getParents(Individual $person) {
184		$father = null;
185		$mother = null;
186		$html   = sprintf(self::TTL, I18N::translate('Parents'));
187		$family = $person->getPrimaryChildFamily();
188		if (!Auth::isSearchEngine() && $person->canShowName() && $family !== null) {
189			$father = $family->getHusband();
190			$mother = $family->getWife();
191			$html .= $this->getHTML($father) .
192					 $this->getHTML($mother);
193
194			// Can only have a step parent if one & only one parent found at this point
195			if ($father instanceof Individual xor $mother instanceof Individual) {
196				$stepParents = '';
197				foreach ($person->getChildStepFamilies() as $family) {
198					if (!$father instanceof Individual) {
199						$stepParents .= $this->getHTML($family->getHusband());
200					} else {
201						$stepParents .= $this->getHTML($family->getWife());
202					}
203				}
204				if ($stepParents) {
205					$relationship = $father instanceof Individual ?
206						I18N::translateContext("father’s wife", "step-mother") : I18N::translateContext("mother’s husband", "step-father");
207					$html .= sprintf(self::TTL, $relationship) . $stepParents;
208				}
209			}
210		}
211		if (!($father instanceof Individual || $mother instanceof Individual)) {
212			$html .= sprintf(self::MSG, I18N::translateContext('unknown family', 'unknown'));
213		}
214
215		return $html;
216	}
217
218	/**
219	 * @param Individual $person
220	 *
221	 * @return string
222	 */
223	private function getFamily(Individual $person) {
224		$html = '';
225		if ($person->canShowName() && !Auth::isSearchEngine()) {
226			foreach ($person->getSpouseFamilies() as $family) {
227				$spouse = $family->getSpouse($person);
228				$html .= $this->getHTML($spouse, true);
229				$children = $family->getChildren();
230				if (count($children) > 0) {
231					$html .= "<ul class='clist'>";
232					foreach ($children as $child) {
233						$html .= '<li>' . $this->getHTML($child) . '</li>';
234					}
235					$html .= '</ul>';
236				}
237			}
238		}
239		if (!$html) {
240			$html = sprintf(self::MSG, I18N::translate('none'));
241		}
242
243		return sprintf(self::TTL, I18N::translate('Family')) . $html;
244	}
245
246}
247