1<?php 2 3/** 4 * webtrees: online genealogy 5 * Copyright (C) 2023 webtrees development team 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 */ 17 18declare(strict_types=1); 19 20namespace Fisharebest\Webtrees\Http\RequestHandlers; 21 22use Fisharebest\Webtrees\Auth; 23use Fisharebest\Webtrees\Date; 24use Fisharebest\Webtrees\I18N; 25use Psr\Http\Message\ResponseInterface; 26use Psr\Http\Message\ServerRequestInterface; 27use Psr\Http\Server\RequestHandlerInterface; 28 29use function array_keys; 30use function response; 31use function strip_tags; 32use function view; 33 34/** 35 * Show help text. 36 */ 37class HelpText implements RequestHandlerInterface 38{ 39 private const FRENCH_DATES = [ 40 '@#DFRENCH R@ 12', 41 '@#DFRENCH R@ VEND 12', 42 'ABT @#DFRENCH R@ BRUM 12', 43 'BET @#DFRENCH R@ FRIM 12 AND @#DFRENCH R@ NIVO 12', 44 'FROM @#DFRENCH R@ PLUV 12 TO @#DFRENCH R@ VENT 12', 45 'AFT @#DFRENCH R@ GERM 12', 46 'BEF @#DFRENCH R@ FLOR 12', 47 'ABT @#DFRENCH R@ PRAI 12', 48 'FROM @#DFRENCH R@ MESS 12', 49 'TO @#DFRENCH R@ THER 12', 50 'EST @#DFRENCH R@ FRUC 12', 51 '@#DFRENCH R@ 03 COMP 12', 52 ]; 53 54 private const HIJRI_DATES = [ 55 '@#DHIJRI@ 1497', 56 '@#DHIJRI@ MUHAR 1497', 57 'ABT @#DHIJRI@ SAFAR 1497', 58 'BET @#DHIJRI@ RABIA 1497 AND @#DHIJRI@ RABIT 1497', 59 'FROM @#DHIJRI@ JUMAA 1497 TO @#DHIJRI@ JUMAT 1497', 60 'AFT @#DHIJRI@ RAJAB 1497', 61 'BEF @#DHIJRI@ SHAAB 1497', 62 'ABT @#DHIJRI@ RAMAD 1497', 63 'FROM @#DHIJRI@ SHAWW 1497', 64 'TO @#DHIJRI@ DHUAQ 1497', 65 '@#DHIJRI@ 03 DHUAH 1497', 66 ]; 67 68 private const JALALI_DATES = [ 69 '@#DJALALI@ 1497', 70 '@#DJALALI@ FARVA 1497', 71 'ABT @#DJALALI@ ORDIB 1497', 72 'BET @#DJALALI@ KHORD 1497 AND @#DHIJRI@ TIR 1497', 73 'FROM @#DJALALI@ MORDA 1497 TO @#DHIJRI@ SHAHR 1497', 74 'AFT @#DJALALI@ MEHR 1497', 75 'BEF @#DJALALI@ ABAN 1497', 76 'ABT @#DJALALI@ AZAR 1497', 77 'FROM @#DJALALI@ DEY 1497', 78 'TO @#DJALALI@ BAHMA 1497', 79 '@#DJALALI@ 03 XXXXX 1497', 80 ]; 81 82 private const JEWISH_DATES = [ 83 '@#DHEBREW@ 5481', 84 '@#DHEBREW@ TSH 5481', 85 'ABT @#DHEBREW@ CSH 5481', 86 'BET @#DHEBREW@ KSL 5481 AND @#DHEBREW@ TVT 5481', 87 'FROM @#DHEBREW@ SHV 5481 TO @#DHEBREW@ ADR 5481', 88 'AFT @#DHEBREW@ ADR 5481', 89 'AFT @#DHEBREW@ ADS 5480', 90 'BEF @#DHEBREW@ NSN 5481', 91 'ABT @#DHEBREW@ IYR 5481', 92 'FROM @#DHEBREW@ SVN 5481', 93 'TO @#DHEBREW@ TMZ 5481', 94 'EST @#DHEBREW@ AAV 5481', 95 '@#DHEBREW@ 03 ELL 5481', 96 ]; 97 98 private const JULIAN_DATES = [ 99 '@#DJULIAN@ 14 JAN 1700', 100 '@#DJULIAN@ 44 B.C.', 101 '@#DJULIAN@ 20 FEB 1742/43', 102 'BET @#DJULIAN@ 01 SEP 1752 AND @#DGREGORIAN@ 30 SEP 1752', 103 ]; 104 105 private const DATE_SHORTCUTS = [ 106 '1900' => [], 107 'JAN 1900' => [], 108 'FEB 1900' => [], 109 'MAR 1900' => [], 110 'APR 1900' => [], 111 'MAY 1900' => [], 112 'JUN 1900' => [], 113 'JUL 1900' => [], 114 'AUG 1900' => [], 115 'SEP 1900' => [], 116 'OCT 1900' => [], 117 'NOV 1900' => [], 118 'DEC 1900' => [], 119 'ABT 1900' => ['~1900'], 120 'EST 1900' => ['*1900'], 121 'CAL 1900' => ['#1900'], 122 'INT 1900 (...)' => [], 123 ]; 124 125 private const DATE_RANGE_SHORTCUTS = [ 126 'BET 1900 AND 1910' => ['1900-1910'], 127 'AFT 1900' => ['>1900'], 128 'BEF 1910' => ['<1910'], 129 'BET JAN 1900 AND MAR 1900' => ['Q1 1900'], 130 'BET APR 1900 AND JUN 1900' => ['Q2 1900'], 131 'BET JUL 1900 AND SEP 1900' => ['Q3 1900'], 132 'BET OCT 1900 AND DEC 1900' => ['Q4 1900'], 133 ]; 134 135 private const DATE_PERIOD_SHORTCUTS = [ 136 'FROM 1900 TO 1910' => ['1900~1910'], 137 'FROM 1900' => ['1900-'], 138 'TO 1910' => ['-1900'], 139 ]; 140 141 private const DMY_SHORTCUTS = [ 142 '11 DEC 1913' => [ 143 '11/12/1913', 144 '11-12-1913', 145 '11.12.1913', 146 ], 147 '01 FEB 2003' => [ 148 '01/02/03', 149 '01-02-03', 150 '01.02.03', 151 ], 152 ]; 153 154 private const MDY_SHORTCUTS = [ 155 '11 DEC 1913' => [ 156 '12/11/1913', 157 '12-11-1913', 158 '12.11.1913', 159 ], 160 '01 FEB 2003' => [ 161 '02/01/03', 162 '02-01-03', 163 '02.01.03', 164 ], 165 ]; 166 167 private const YMD_SHORTCUTS = [ 168 '11 DEC 1913' => [ 169 '11/12/1913', 170 '11-12-1913', 171 '11.12.1913', 172 ], 173 '01 FEB 2003' => [ 174 '03/02/01', 175 '03-02-01', 176 '03.02.01', 177 ], 178 ]; 179 180 /** 181 * @param ServerRequestInterface $request 182 * 183 * @return ResponseInterface 184 */ 185 public function handle(ServerRequestInterface $request): ResponseInterface 186 { 187 $topic = $request->getAttribute('topic'); 188 189 $dmy = I18N::language()->dateOrder(); 190 191 switch ($topic) { 192 case 'DATE': 193 switch ($dmy) { 194 case 'YMD': 195 $date_shortcuts = self::DATE_SHORTCUTS + self::YMD_SHORTCUTS; 196 break; 197 case 'MDY': 198 $date_shortcuts = self::DATE_SHORTCUTS + self::MDY_SHORTCUTS; 199 break; 200 case 'DMY': 201 default: 202 $date_shortcuts = self::DATE_SHORTCUTS + self::DMY_SHORTCUTS; 203 break; 204 } 205 206 $title = I18N::translate('Date'); 207 $text = view('help/date', [ 208 'date_dates' => $this->formatDates(array_keys($date_shortcuts)), 209 'date_shortcuts' => $date_shortcuts, 210 'date_period_dates' => $this->formatDates(array_keys(self::DATE_PERIOD_SHORTCUTS)), 211 'date_period_shortcuts' => self::DATE_PERIOD_SHORTCUTS, 212 'date_range_dates' => $this->formatDates(array_keys(self::DATE_RANGE_SHORTCUTS)), 213 'date_range_shortcuts' => self::DATE_RANGE_SHORTCUTS, 214 'french_dates' => $this->formatDates(self::FRENCH_DATES), 215 'hijri_dates' => $this->formatDates(self::HIJRI_DATES), 216 'jalali_dates' => $this->formatDates(self::JALALI_DATES), 217 'jewish_dates' => $this->formatDates(self::JEWISH_DATES), 218 'julian_dates' => $this->formatDates(self::JULIAN_DATES), 219 ]); 220 break; 221 222 case 'NAME': 223 $title = I18N::translate('Name'); 224 $text = view('help/name'); 225 break; 226 227 case 'SURN': 228 $title = I18N::translate('Surname'); 229 $text = view('help/surname'); 230 break; 231 232 case 'OBJE': 233 $title = I18N::translate('Media object'); 234 $text = view('help/media-object'); 235 break; 236 237 case 'PLAC': 238 $title = I18N::translate('Place'); 239 $text = view('help/place'); 240 break; 241 242 case 'RESN': 243 $title = I18N::translate('Restriction'); 244 $text = view('help/restriction'); 245 break; 246 247 case 'ROMN': 248 $title = I18N::translate('Romanized'); 249 $text = view('help/romanized'); 250 break; 251 252 case '_HEB': 253 $title = I18N::translate('Hebrew'); 254 $text = view('help/hebrew'); 255 break; 256 257 case 'data-fixes': 258 $title = I18N::translate('Data fixes'); 259 $text = view('help/data-fixes'); 260 break; 261 262 case 'edit_SOUR_EVEN': 263 $title = I18N::translate('Associate events with this source'); 264 $text = view('help/source-events'); 265 break; 266 267 case 'pending_changes': 268 $title = I18N::translate('Pending changes'); 269 $text = view('help/pending-changes', [ 270 'is_admin' => Auth::isAdmin(), 271 ]); 272 break; 273 274 case 'relationship-privacy': 275 $title = I18N::translate('Restrict to immediate family'); 276 $text = view('help/relationship-privacy'); 277 break; 278 279 default: 280 $title = I18N::translate('Help'); 281 $text = I18N::translate('The help text has not been written for this item.'); 282 break; 283 } 284 285 $html = view('modals/help', [ 286 'title' => $title, 287 'text' => $text, 288 ]); 289 290 return response($html); 291 } 292 293 /** 294 * Format GEDCOM dates in the local language. 295 * 296 * @param array<string>|array<int> $gedcom_dates 297 * 298 * @return array<string> 299 */ 300 private function formatDates(array $gedcom_dates): array 301 { 302 $dates = []; 303 304 foreach ($gedcom_dates as $gedcom_date) { 305 // PHP converts numeric array keys ('1900') to integers (1900), so reverse this. 306 $gedcom_date = (string) $gedcom_date; 307 308 $date = new Date($gedcom_date); 309 $dates[$gedcom_date] = strip_tags($date->display()); 310 } 311 312 return $dates; 313 } 314} 315