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