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