1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2019 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; 17 18/** 19 * Defined in session.php 20 * 21 * @global Tree $WT_TREE 22 */ 23global $WT_TREE; 24 25use Fisharebest\Webtrees\Controller\PageController; 26use Fisharebest\Webtrees\Date\FrenchDate; 27use Fisharebest\Webtrees\Date\GregorianDate; 28use Fisharebest\Webtrees\Date\HijriDate; 29use Fisharebest\Webtrees\Date\JalaliDate; 30use Fisharebest\Webtrees\Date\JewishDate; 31use Fisharebest\Webtrees\Date\JulianDate; 32use Fisharebest\Webtrees\Functions\FunctionsDb; 33use Fisharebest\Webtrees\Functions\FunctionsPrint; 34 35define('WT_SCRIPT_NAME', 'calendar.php'); 36require './includes/session.php'; 37 38$CALENDAR_FORMAT = $WT_TREE->getPreference('CALENDAR_FORMAT'); 39 40$cal = Filter::get('cal', '@#D[A-Z ]+@'); 41$day = Filter::get('day', '\d\d?'); 42$month = Filter::get('month', '[A-Z]{3,5}'); 43$year = Filter::get('year', '\d{1,4}(?: B\.C\.)?|\d\d\d\d\/\d\d|\d+(-\d+|[?]+)?'); 44$view = Filter::get('view', 'day|month|year', 'day'); 45$filterev = Filter::get('filterev', '[_A-Z-]*', 'BIRT-MARR-DEAT'); 46$filterof = Filter::get('filterof', 'all|living|recent', 'all'); 47$filtersx = Filter::get('filtersx', '[MF]', ''); 48 49if ($cal . $day . $month . $year === '') { 50 // No date specified? Use the most likely calendar 51 $cal = I18N::defaultCalendar()->gedcomCalendarEscape(); 52} 53 54// Create a CalendarDate from the parameters 55 56// We cannot display new-style/old-style years, so convert to new style 57if (preg_match('/^(\d\d)\d\d\/(\d\d)$/', $year, $match)) { 58 $year = $match[1] . $match[2]; 59} 60 61// advanced-year "year range" 62if (preg_match('/^(\d+)-(\d+)$/', $year, $match)) { 63 if (strlen($match[1]) > strlen($match[2])) { 64 $match[2] = substr($match[1], 0, strlen($match[1]) - strlen($match[2])) . $match[2]; 65 } 66 $ged_date = new Date("FROM {$cal} {$match[1]} TO {$cal} {$match[2]}"); 67 $view = 'year'; 68} else { 69 // advanced-year "decade/century wildcard" 70 if (preg_match('/^(\d+)(\?+)$/', $year, $match)) { 71 $y1 = $match[1] . str_replace('?', '0', $match[2]); 72 $y2 = $match[1] . str_replace('?', '9', $match[2]); 73 $ged_date = new Date("FROM {$cal} {$y1} TO {$cal} {$y2}"); 74 $view = 'year'; 75 } else { 76 if ($year < 0) { 77 $year = (-$year) . ' B.C.'; 78 } // need BC to parse date 79 $ged_date = new Date("{$cal} {$day} {$month} {$year}"); 80 $year = $ged_date->minimumDate()->y; // need negative year for year entry field. 81 } 82} 83$cal_date = $ged_date->minimumDate(); 84 85// Fill in any missing bits with todays date 86$today = $cal_date->today(); 87if ($cal_date->d === 0) { 88 $cal_date->d = $today->d; 89} 90if ($cal_date->m === 0) { 91 $cal_date->m = $today->m; 92} 93if ($cal_date->y === 0) { 94 $cal_date->y = $today->y; 95} 96 97$cal_date->setJdFromYmd(); 98 99if ($year === 0) { 100 $year = $cal_date->y; 101} 102 103// Extract values from date 104$days_in_month = $cal_date->daysInMonth(); 105$days_in_week = $cal_date->daysInWeek(); 106$cal_month = $cal_date->format('%O'); 107$today_month = $today->format('%O'); 108 109// Invalid dates? Go to monthly view, where they'll be found. 110if ($cal_date->d > $days_in_month && $view === 'day') { 111 $view = 'month'; 112} 113 114// All further uses of $cal are to generate URLs 115$cal = rawurlencode($cal); 116 117$controller = new PageController; 118$controller->setPageTitle(I18N::translate('Anniversary calendar')); 119 120switch ($view) { 121 case 'day': 122 $controller->setPageTitle(I18N::translate('On this day…') . ' ' . $ged_date->display(false)); 123 break; 124 case 'month': 125 $controller->setPageTitle(I18N::translate('In this month…') . ' ' . $ged_date->display(false, '%F %Y')); 126 break; 127 case 'year': 128 $controller->setPageTitle(I18N::translate('In this year…') . ' ' . $ged_date->display(false, '%Y')); 129 break; 130} 131 132$controller->pageHeader(); 133 134?> 135<div id="calendar-page"> 136 <h2 class="center"><?php echo $controller->getPageTitle() ?></h2> 137 138 <form name="dateform"> 139 <input type="hidden" name="cal" value="<?php echo $cal ?>"> 140 <input type="hidden" name="day" value="<?php echo $cal_date->d ?>"> 141 <input type="hidden" name="month" value="<?php echo $cal_month ?>"> 142 <input type="hidden" name="year" value="<?php echo $cal_date->y ?>"> 143 <input type="hidden" name="view" value="<?php echo $view ?>"> 144 <input type="hidden" name="filterev" value="<?php echo $filterev ?>"> 145 <input type="hidden" name="filtersx" value="<?php echo $filtersx ?>"> 146 <input type="hidden" name="filterof" value="<?php echo $filterof ?>"> 147 148 <table class="facts_table width100"> 149 <tr> 150 <td class="descriptionbox vmiddle"> 151 <?php echo I18N::translate('Day') ?> 152 </td> 153 <td colspan="3" class="optionbox"> 154 <?php 155 for ($d = 1; $d <= $days_in_month; $d++) { 156 // Format the day number using the calendar 157 $tmp = new Date($cal_date->format("%@ {$d} %O %E")); 158 $d_fmt = $tmp->minimumDate()->format('%j'); 159 if ($d === $cal_date->d) { 160 echo '<span class="error">', $d_fmt, '</span>'; 161 } else { 162 echo '<a href="?cal=', $cal, '&day=', $d, '&month=', $cal_month, '&year=', $cal_date->y, '&filterev=', $filterev, '&filterof=', $filterof, '&filtersx=', $filtersx, '&view=', $view, '">', $d_fmt, '</a>'; 163 } 164 echo ' | '; 165 } 166 ?> 167 <a href="?cal=<?php echo $cal ?>&day=<?php echo $today->d ?>&month=<?php echo $today_month ?>&year=<?php echo $today->y ?>&filterev=<?php echo $filterev ?>&filterof=<?php echo $filterof ?>&filtersx=<?php echo $filtersx ?>&view=<?php echo $view ?>"> 168 <b><?php $tmp = new Date($today->format('%@ %A %O %E')); echo $tmp->display() ?></b> 169 </a> 170 </td> 171 </tr> 172 <tr> 173 <td class="descriptionbox"> 174 <?php echo I18N::translate('Month') ?> 175 </td> 176 <td class="optionbox" colspan="3"> 177 <?php 178 for ($n = 1, $months_in_year = $cal_date->monthsInYear(); $n <= $months_in_year; ++$n) { 179 $month_name = $cal_date->monthNameNominativeCase($n, $cal_date->isLeapYear()); 180 $m = array_search($n, $cal_date::$MONTH_ABBREV); 181 if ($n === 6 && $cal_date instanceof JewishDate && !$cal_date->isLeapYear()) { 182 // No month 6 in Jewish non-leap years. 183 continue; 184 } 185 if ($n === 7 && $cal_date instanceof JewishDate && !$cal_date->isLeapYear()) { 186 // Month 7 is ADR in Jewish non-leap years. 187 $m = 'ADR'; 188 } 189 if ($n === $cal_date->m) { 190 $month_name = '<span class="error">' . $month_name . '</span>'; 191 } 192 echo '<a href="?cal=', $cal, '&day=', $cal_date->d, '&month=', $m, '&year=', $cal_date->y, '&filterev=', $filterev, '&filterof=', $filterof, '&filtersx=', $filtersx, '&view=', $view, '">', $month_name, '</a>'; 193 echo ' | '; 194 } 195 ?> 196 <a href="?cal=<?php echo $cal ?>&day=<?php echo min($cal_date->d, $today->daysInMonth()) ?>&month=<?php echo $today_month ?>&year=<?php echo $today->y ?>&filterev=<?php echo $filterev ?>&filterof=<?php echo $filterof ?>&filtersx=<?php echo $filtersx ?>&view=<?php echo $view ?>"> 197 <b><?php echo $today->format('%F %Y') ?></b> 198 </a> 199 </td> 200 </tr> 201 <tr> 202 <td class="descriptionbox vmiddle"> 203 <label for="year"><?php echo I18N::translate('Year') ?></label> 204 </td> 205 <td class="optionbox vmiddle"> 206 <a href="?cal=<?php echo $cal ?>&day=<?php echo $cal_date->d ?>&month=<?php echo $cal_month ?>&year=<?php echo $cal_date->y === 1 ? -1 : $cal_date->y - 1 ?>&filterev=<?php echo $filterev ?>&filterof=<?php echo $filterof ?>&filtersx=<?php echo $filtersx ?>&view=<?php echo $view ?>"> 207 -1 208 </a> 209 <input type="text" id="year" name="year" value="<?php echo $year ?>" size="4"> 210 <a href="?cal=<?php echo $cal ?>&day=<?php echo $cal_date->d ?>&month=<?php echo $cal_month ?>&year=<?php echo $cal_date->y === -1 ? 1 : $cal_date->y + 1 ?>&filterev=<?php echo $filterev ?>&filterof=<?php echo $filterof ?>&filtersx=<?php echo $filtersx ?>&view=<?php echo $view ?>"> 211 +1 212 </a> 213 | 214 <a href="?cal=<?php echo $cal ?>&day=<?php echo $cal_date->d ?>&month=<?php echo $cal_month ?>&year=<?php echo $today->y ?>&filterev=<?php echo $filterev ?>&filterof=<?php echo $filterof ?>&filtersx=<?php echo $filtersx ?>&view=<?php echo $view ?>"> 215 <?php echo $today->format('%Y') ?> 216 </a> 217 <?php echo FunctionsPrint::helpLink('annivers_year_select') ?> 218 </td> 219 220 <td class="descriptionbox vmiddle"> 221 <?php echo I18N::translate('Show') ?> 222 </td> 223 224 <td class="optionbox vmiddle"> 225 <?php if (!$WT_TREE->getPreference('HIDE_LIVE_PEOPLE') || Auth::check()): ?> 226 <select class="list_value" name="filterof" onchange="document.dateform.submit();"> 227 <option value="all" <?php echo $filterof === 'all' ? 'selected' : '' ?>> 228 <?php echo I18N::translate('All individuals') ?> 229 </option> 230 <option value="living" <?php echo $filterof === 'living' ? 'selected' : '' ?>> 231 <?php echo I18N::translate('Living individuals') ?> 232 </option> 233 <option value="recent" <?php echo $filterof === 'recent' ? 'selected' : '' ?>> 234 <?php echo I18N::translate('Recent years (< 100 yrs)') ?> 235 </option> 236 </select> 237 <?php endif; ?> 238 239 <a title="<?php echo I18N::translate('All individuals') ?>" href="?cal=<?php echo $cal ?>&day=<?php echo $cal_date->d ?>&month=<?php echo $cal_month ?>&year=<?php echo $cal_date->y ?>&filterev=<?php echo $filterev ?>&filterof=<?php echo $filterof ?>&view=<?php echo $view ?>"> 240 <i class="<?php echo $filtersx === '' ? 'icon-sex_m_15x15' : 'icon-sex_m_9x9' ?>"></i> 241 <i class="<?php echo $filtersx === '' ? 'icon-sex_f_15x15' : 'icon-sex_f_9x9' ?>"></i> 242 </a> 243 | 244 <a title="<?php echo I18N::translate('Males') ?>" href="?cal=<?php echo $cal ?>&day=<?php echo $cal_date->d ?>&month=<?php echo $cal_month ?>&year=<?php echo $cal_date->y ?>&filterev=<?php echo $filterev ?>&filterof=<?php echo $filterof ?>&filtersx=M&view=<?php echo $view ?>"> 245 <i class="<?php echo $filtersx === 'M' ? 'icon-sex_m_15x15' : 'icon-sex_m_9x9' ?>"></i> 246 </a> 247 | 248 <a title="<?php echo I18N::translate('Females') ?>" href="?cal=<?php echo $cal ?>&day=<?php echo $cal_date->d ?>&month=<?php echo $cal_month ?>&year=<?php echo $cal_date->y ?>&filterev=<?php echo $filterev ?>&filterof=<?php echo $filterof ?>&filtersx=F&view=<?php echo $view ?>"> 249 <i class="<?php echo $filtersx === 'F' ? 'icon-sex_f_15x15' : 'icon-sex_f_9x9' ?>"></i> 250 </a> 251 252 <select class="list_value" name="filterev" onchange="document.dateform.submit();"> 253 <option value="BIRT-MARR-DEAT" <?php echo $filterev === 'BIRT-MARR-DEAT' ? 'selected' : '' ?>> 254 <?php echo I18N::translate('Vital records') ?> 255 </option> 256 <option value="" <?php echo $filterev === '' ? 'selected' : '' ?>> 257 <?php echo I18N::translate('All') ?> 258 </option> 259 <option value="BIRT" <?php echo $filterev === 'BIRT' ? 'selected' : '' ?>> 260 <?php echo GedcomTag::getLabel('BIRT') ?> 261 </option> 262 <option value="BAPM-CHR-CHRA" <?php echo $filterev === 'BAPM-CHR-CHRA' ? 'selected' : '' ?>> 263 <?php echo GedcomTag::getLabel('BAPM') ?> 264 </option> 265 <option value="MARR-_COML-_NMR" <?php echo $filterev === 'MARR-_COML-_NMR' ? 'selected' : '' ?>> 266 <?php echo GedcomTag::getLabel('MARR') ?> 267 </option> 268 <option value="DIV-_SEPR" <?php echo $filterev === 'DIV-_SEPR' ? 'selected' : '' ?>> 269 <?php echo GedcomTag::getLabel('DIV') ?> 270 </option> 271 <option value="DEAT" <?php echo $filterev === 'DEAT' ? 'selected' : '' ?>> 272 <?php echo GedcomTag::getLabel('DEAT') ?> 273 </option> 274 <option value="BURI" <?php echo $filterev === 'BURI' ? 'selected' : '' ?>> 275 <?php echo GedcomTag::getLabel('BURI') ?> 276 </option> 277 <option value="IMMI,EMIG" <?php echo $filterev === 'IMMI,EMIG' ? 'selected' : '' ?>> 278 <?php echo GedcomTag::getLabel('EMIG') ?> 279 </option> 280 <option value="EVEN" <?php echo $filterev === 'EVEN' ? 'selected' : '' ?>> 281 <?php echo I18N::translate('Custom event') ?> 282 </option> 283 </select> 284 </td> 285 </tr> 286 </table> 287 288 <table class="width100"> 289 <tr> 290 <td class="topbottombar width50"> 291 <a class="<?php echo $view === 'day' ? 'error' : '' ?>" href="?cal=<?php echo $cal ?>&day=<?php echo $cal_date->d ?>&month=<?php echo $cal_month ?>&year=<?php echo $cal_date->y ?>&filterev=<?php echo $filterev ?>&filterof=<?php echo $filterof ?>&filtersx=<?php echo $filtersx ?>&view=day"> 292 <?php echo I18N::translate('View this day') ?> 293 </a> 294 | 295 <a class="<?php echo $view === 'month' ? 'error' : '' ?>" href="?cal=<?php echo $cal ?>&day=<?php echo $cal_date->d ?>&month=<?php echo $cal_month ?>&year=<?php echo $cal_date->y ?>&filterev=<?php echo $filterev ?>&filterof=<?php echo $filterof ?>&filtersx=<?php echo $filtersx ?>&view=month"> 296 <?php echo I18N::translate('View this month') ?> 297 </a> 298 | 299 <a class="<?php echo $view === 'year' ? 'error' : '' ?>" href="?cal=<?php echo $cal ?>&day=<?php echo $cal_date->d ?>&month=<?php echo $cal_month ?>&year=<?php echo $cal_date->y ?>&filterev=<?php echo $filterev ?>&filterof=<?php echo $filterof ?>&filtersx=<?php echo $filtersx ?>&view=year"> 300 <?php echo I18N::translate('View this year') ?> 301 </a> 302 </td> 303 <td class="topbottombar width50"> 304 <?php 305 $n = 0; 306 foreach (Date::calendarNames() as $newcal => $cal_name) { 307 $tmp = $cal_date->convertToCalendar($newcal); 308 if ($tmp->inValidRange()) { 309 if ($n++) { 310 echo ' | '; 311 } 312 if (get_class($tmp) === get_class($cal_date)) { 313 echo '<span class="error">', $cal_name, '</span>'; 314 } else { 315 $newcalesc = urlencode($tmp->format('%@')); 316 $tmpmonth = $tmp->format('%O'); 317 echo '<a href="?cal=', $newcalesc, '&day=', $tmp->d, '&month=', $tmpmonth, '&year=', $tmp->y, '&filterev=', $filterev, '&filterof=', $filterof, '&filtersx=', $filtersx, '&view=', $view, '">', $cal_name, '</a>'; 318 } 319 } 320 } 321 ?> 322 </td> 323 </tr> 324 </table> 325 </form> 326<?php 327 328// Fetch data for day/month/year views 329$found_facts = array(); 330 331switch ($view) { 332 case 'day': 333 $found_facts = apply_filter(FunctionsDb::getAnniversaryEvents($cal_date->minJD, $filterev, $WT_TREE), $filterof, $filtersx); 334 break; 335 case 'month': 336 $cal_date->d = 0; 337 $cal_date->setJdFromYmd(); 338 // Make a separate list for each day. Unspecified/invalid days go in day 0. 339 for ($d = 0; $d <= $days_in_month; ++$d) { 340 $found_facts[$d] = array(); 341 } 342 // Fetch events for each day 343 for ($jd = $cal_date->minJD; $jd <= $cal_date->maxJD; ++$jd) { 344 foreach (apply_filter(FunctionsDb::getAnniversaryEvents($jd, $filterev, $WT_TREE), $filterof, $filtersx) as $fact) { 345 $tmp = $fact->getDate()->minimumDate(); 346 if ($tmp->d >= 1 && $tmp->d <= $tmp->daysInMonth()) { 347 // If the day is valid (for its own calendar), display it in the 348 // anniversary day (for the display calendar). 349 $found_facts[$jd - $cal_date->minJD + 1][] = $fact; 350 } else { 351 // Otherwise, display it in the "Day not set" box. 352 $found_facts[0][] = $fact; 353 } 354 } 355 } 356 break; 357 case 'year': 358 $cal_date->m = 0; 359 $cal_date->setJdFromYmd(); 360 $found_facts = apply_filter(FunctionsDb::getCalendarEvents($ged_date->minimumJulianDay(), $ged_date->maximumJulianDay(), $filterev, $WT_TREE), $filterof, $filtersx); 361 // Eliminate duplicates (e.g. BET JUL 1900 AND SEP 1900 will appear twice in 1900) 362 $found_facts = array_unique($found_facts); 363 break; 364} 365 366// Group the facts by family/individual 367$indis = array(); 368$fams = array(); 369$cal_facts = array(); 370 371switch ($view) { 372 case 'year': 373 case 'day': 374 foreach ($found_facts as $fact) { 375 $record = $fact->getParent(); 376 $xref = $record->getXref(); 377 if ($record instanceof Individual) { 378 if (empty($indis[$xref])) { 379 $indis[$xref] = calendar_fact_text($fact, true); 380 } else { 381 $indis[$xref] .= '<br>' . calendar_fact_text($fact, true); 382 } 383 } elseif ($record instanceof Family) { 384 if (empty($indis[$xref])) { 385 $fams[$xref] = calendar_fact_text($fact, true); 386 } else { 387 $fams[$xref] .= '<br>' . calendar_fact_text($fact, true); 388 } 389 } 390 } 391 break; 392 case 'month': 393 foreach ($found_facts as $d => $facts) { 394 $cal_facts[$d] = array(); 395 foreach ($facts as $fact) { 396 $xref = $fact->getParent()->getXref(); 397 if (empty($cal_facts[$d][$xref])) { 398 $cal_facts[$d][$xref] = calendar_fact_text($fact, false); 399 } else { 400 $cal_facts[$d][$xref] .= '<br>' . calendar_fact_text($fact, false); 401 } 402 } 403 } 404 break; 405} 406 407switch ($view) { 408 case 'year': 409 case 'day': 410 $males = 0; 411 $females = 0; 412 echo '<table class="width100"><tr>'; 413 echo '<td class="descriptionbox center width50"><i class="icon-indis"></i>', I18N::translate('Individuals'), '</td>'; 414 echo '<td class="descriptionbox center width50"><i class="icon-cfamily"></i>', I18N::translate('Families'), '</td>'; 415 echo '</tr><tr>'; 416 echo '<td class="optionbox wrap">'; 417 418 $content = calendar_list_text($indis, '<li>', '</li>', true); 419 if ($content) { 420 echo '<ul>', $content, '</ul>'; 421 } 422 423 echo '</td>'; 424 echo '<td class="optionbox wrap">'; 425 426 $content = calendar_list_text($fams, '<li>', '</li>', true); 427 if ($content) { 428 echo '<ul>', $content, '</ul>'; 429 } 430 431 echo '</td>'; 432 echo '</tr><tr>'; 433 echo '<td class="descriptionbox">', I18N::translate('Total individuals: %s', count($indis)); 434 echo '<br>'; 435 echo '<i class="icon-sex_m_15x15" title="', I18N::translate('Males'), '"></i> ', $males, ' '; 436 echo '<i class="icon-sex_f_15x15" title="', I18N::translate('Females'), '"></i> ', $females, ' '; 437 if (count($indis) !== $males + $females) { 438 echo '<i class="icon-sex_u_15x15" title="', I18N::translate('All individuals'), '"></i> ', count($indis) - $males - $females; 439 } 440 echo '</td>'; 441 echo '<td class="descriptionbox">', I18N::translate('Total families: %s', count($fams)), '</td>'; 442 echo '</tr></table>'; 443 444 break; 445 case 'month': 446 // We use JD%7 = 0/Mon…6/Sun. Standard definitions use 0/Sun…6/Sat. 447 $week_start = (I18N::firstDay() + 6) % 7; 448 $weekend_start = (I18N::weekendStart() + 6) % 7; 449 $weekend_end = (I18N::weekendEnd() + 6) % 7; 450 // The french calendar has a 10-day week, which starts on primidi 451 if ($days_in_week === 10) { 452 $week_start = 0; 453 $weekend_start = -1; 454 $weekend_end = -1; 455 } 456 echo '<table class="width100"><thead><tr>'; 457 for ($week_day = 0; $week_day < $days_in_week; ++$week_day) { 458 $day_name = $cal_date->dayNames(($week_day + $week_start) % $days_in_week); 459 if ($week_day == $weekend_start || $week_day == $weekend_end) { 460 echo '<th class="descriptionbox weekend" width="' . (100 / $days_in_week) . '%">', $day_name, '</th>'; 461 } else { 462 echo '<th class="descriptionbox" width="' . (100 / $days_in_week) . '%">', $day_name, '</th>'; 463 } 464 } 465 echo '</tr>'; 466 echo '</thead>'; 467 echo '<tbody>'; 468 // Print days 1 to n of the month, but extend to cover "empty" days before/after the month to make whole weeks. 469 // e.g. instead of 1 -> 30 (=30 days), we might have -1 -> 33 (=35 days) 470 $start_d = 1 - ($cal_date->minJD - $week_start) % $days_in_week; 471 $end_d = $days_in_month + ($days_in_week - ($cal_date->maxJD - $week_start + 1) % $days_in_week) % $days_in_week; 472 // Make sure that there is an empty box for any leap/missing days 473 if ($start_d === 1 && $end_d === $days_in_month && count($found_facts[0]) > 0) { 474 $end_d += $days_in_week; 475 } 476 for ($d = $start_d; $d <= $end_d; ++$d) { 477 if (($d + $cal_date->minJD - $week_start) % $days_in_week === 1) { 478 echo '<tr>'; 479 } 480 echo '<td class="optionbox wrap">'; 481 if ($d < 1 || $d > $days_in_month) { 482 if (count($cal_facts[0]) > 0) { 483 echo '<span class="cal_day">', I18N::translate('Day not set'), '</span><br style="clear: both;">'; 484 echo '<div class="details1" style="height: 180px; overflow: auto;">'; 485 echo calendar_list_text($cal_facts[0], '', '', false); 486 echo '</div>'; 487 $cal_facts[0] = array(); 488 } 489 } else { 490 // Format the day number using the calendar 491 $tmp = new Date($cal_date->format("%@ {$d} %O %E")); 492 $d_fmt = $tmp->minimumDate()->format('%j'); 493 if ($d === $today->d && $cal_date->m === $today->m) { 494 echo '<span class="cal_day current_day">', $d_fmt, '</span>'; 495 } else { 496 echo '<span class="cal_day">', $d_fmt, '</span>'; 497 } 498 // Show a converted date 499 foreach (explode('_and_', $CALENDAR_FORMAT) as $convcal) { 500 switch ($convcal) { 501 case 'french': 502 $alt_date = new FrenchDate($cal_date->minJD + $d - 1); 503 break; 504 case 'gregorian': 505 $alt_date = new GregorianDate($cal_date->minJD + $d - 1); 506 break; 507 case 'jewish': 508 $alt_date = new JewishDate($cal_date->minJD + $d - 1); 509 break; 510 case 'julian': 511 $alt_date = new JulianDate($cal_date->minJD + $d - 1); 512 break; 513 case 'hijri': 514 $alt_date = new HijriDate($cal_date->minJD + $d - 1); 515 break; 516 case 'jalali': 517 $alt_date = new JalaliDate($cal_date->minJD + $d - 1); 518 break; 519 default: 520 break 2; 521 } 522 if (get_class($alt_date) !== get_class($cal_date) && $alt_date->inValidRange()) { 523 echo '<span class="rtl_cal_day">' . $alt_date->format("%j %M") . '</span>'; 524 // Just show the first conversion 525 break; 526 } 527 } 528 echo '<br style="clear: both;"><div class="details1" style="height: 180px; overflow: auto;">'; 529 echo calendar_list_text($cal_facts[$d], '', '', false); 530 echo '</div>'; 531 } 532 echo '</td>'; 533 if (($d + $cal_date->minJD - $week_start) % $days_in_week === 0) { 534 echo '</tr>'; 535 } 536 } 537 echo '</tbody>'; 538 echo '</table>'; 539 break; 540} 541echo '</div>'; //close "calendar-page" 542 543/** 544 * Filter a list of anniversaries 545 * 546 * @param Fact[] $facts 547 * @param string $filterof 548 * @param string $filtersx 549 * 550 * @return array 551 */ 552function apply_filter($facts, $filterof, $filtersx) 553{ 554 $filtered = array(); 555 $hundred_years = WT_CLIENT_JD - 36525; 556 foreach ($facts as $fact) { 557 $record = $fact->getParent(); 558 if ($filtersx) { 559 // Filter on sex 560 if ($record instanceof Individual && $filtersx !== $record->getSex()) { 561 continue; 562 } 563 // Can't display families if the sex filter is on. 564 if ($record instanceof Family) { 565 continue; 566 } 567 } 568 // Filter living individuals 569 if ($filterof === 'living') { 570 if ($record instanceof Individual && $record->isDead()) { 571 continue; 572 } 573 if ($record instanceof Family) { 574 $husb = $record->getHusband(); 575 $wife = $record->getWife(); 576 if ($husb && $husb->isDead() || $wife && $wife->isDead()) { 577 continue; 578 } 579 } 580 } 581 // Filter on recent events 582 if ($filterof === 'recent' && $fact->getDate()->maximumJulianDay() < $hundred_years) { 583 continue; 584 } 585 $filtered[] = $fact; 586 } 587 588 return $filtered; 589} 590 591/** 592 * Format an anniversary display. 593 * 594 * @param Fact $fact 595 * @param bool $show_places 596 * 597 * @return string 598 */ 599function calendar_fact_text(Fact $fact, $show_places) 600{ 601 $text = $fact->getLabel() . ' — ' . $fact->getDate()->display(true, null, false); 602 if ($fact->anniv) { 603 $text .= ' (' . I18N::translate('%s year anniversary', $fact->anniv) . ')'; 604 } 605 if ($show_places && $fact->getAttribute('PLAC')) { 606 $text .= ' — ' . $fact->getAttribute('PLAC'); 607 } 608 609 return $text; 610} 611 612/** 613 * Format a list of facts for display 614 * 615 * @param Fact[] $list 616 * @param string $tag1 617 * @param string $tag2 618 * @param bool $show_sex_symbols 619 * 620 * @return string 621 */ 622function calendar_list_text($list, $tag1, $tag2, $show_sex_symbols) 623{ 624 global $males, $females, $WT_TREE; 625 626 $html = ''; 627 628 foreach ($list as $id => $facts) { 629 $tmp = GedcomRecord::getInstance($id, $WT_TREE); 630 $html .= $tag1 . '<a href="' . $tmp->getHtmlUrl() . '">' . $tmp->getFullName() . '</a> '; 631 if ($show_sex_symbols && $tmp instanceof Individual) { 632 switch ($tmp->getSex()) { 633 case 'M': 634 $html .= '<i class="icon-sex_m_9x9" title="' . I18N::translate('Male') . '"></i>'; 635 ++$males; 636 break; 637 case 'F': 638 $html .= '<i class="icon-sex_f_9x9" title="' . I18N::translate('Female') . '"></i>'; 639 ++$females; 640 break; 641 default: 642 $html .= '<i class="icon-sex_u_9x9" title="' . I18N::translateContext('unknown gender', 'Unknown') . '"></i>'; 643 break; 644 } 645 } 646 $html .= '<div class="indent">' . $facts . '</div>' . $tag2; 647 } 648 649 return $html; 650} 651