149a243cbSGreg Roach<?php 23976b470SGreg Roach 349a243cbSGreg Roach/** 449a243cbSGreg Roach * webtrees: online genealogy 549a243cbSGreg Roach * Copyright (C) 2019 webtrees development team 649a243cbSGreg Roach * This program is free software: you can redistribute it and/or modify 749a243cbSGreg Roach * it under the terms of the GNU General Public License as published by 849a243cbSGreg Roach * the Free Software Foundation, either version 3 of the License, or 949a243cbSGreg Roach * (at your option) any later version. 1049a243cbSGreg Roach * This program is distributed in the hope that it will be useful, 1149a243cbSGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 1249a243cbSGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1349a243cbSGreg Roach * GNU General Public License for more details. 1449a243cbSGreg Roach * You should have received a copy of the GNU General Public License 1549a243cbSGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 1649a243cbSGreg Roach */ 17fcfa147eSGreg Roach 1849a243cbSGreg Roachdeclare(strict_types=1); 1949a243cbSGreg Roach 2049a243cbSGreg Roachnamespace Fisharebest\Webtrees\Module; 2149a243cbSGreg Roach 2290a2f718SGreg Roachuse Fisharebest\Localization\Locale\LocaleInterface; 23ade503dfSGreg Roachuse Fisharebest\Webtrees\Auth; 24ade503dfSGreg Roachuse Fisharebest\Webtrees\Fact; 25ade503dfSGreg Roachuse Fisharebest\Webtrees\Gedcom; 26ade503dfSGreg Roachuse Fisharebest\Webtrees\GedcomTag; 27a49d0e3fSGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\AccountEdit; 280c0910bfSGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\ControlPanel; 299b541e4aSGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\HomePage; 3056f9a9c1SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\LoginPage; 3156f9a9c1SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\Logout; 3222e73debSGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\PendingChanges; 337adfb8e5SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\SelectLanguage; 347adfb8e5SGreg Roachuse Fisharebest\Webtrees\Http\RequestHandlers\SelectTheme; 35ade503dfSGreg Roachuse Fisharebest\Webtrees\I18N; 36ade503dfSGreg Roachuse Fisharebest\Webtrees\Individual; 37ade503dfSGreg Roachuse Fisharebest\Webtrees\Menu; 384ca7e03cSGreg Roachuse Fisharebest\Webtrees\Services\ModuleService; 39ade503dfSGreg Roachuse Fisharebest\Webtrees\Tree; 40*7c4add84SGreg Roachuse Fisharebest\Webtrees\User; 41f397d0fdSGreg Roachuse Fisharebest\Webtrees\Webtrees; 426ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 433976b470SGreg Roach 446ccdf4f0SGreg Roachuse function app; 4590a2f718SGreg Roachuse function assert; 467adfb8e5SGreg Roachuse function route; 47ade503dfSGreg Roach 4849a243cbSGreg Roach/** 4949a243cbSGreg Roach * Trait ModuleThemeTrait - default implementation of ModuleThemeInterface 5049a243cbSGreg Roach */ 5149a243cbSGreg Roachtrait ModuleThemeTrait 5249a243cbSGreg Roach{ 53ade503dfSGreg Roach /** 54962ead51SGreg Roach * @return string 55962ead51SGreg Roach */ 56962ead51SGreg Roach abstract public function name(): string; 57962ead51SGreg Roach 58962ead51SGreg Roach /** 59962ead51SGreg Roach * @return string 60962ead51SGreg Roach */ 61962ead51SGreg Roach abstract public function title(): string; 62962ead51SGreg Roach 63962ead51SGreg Roach /** 643d8b2a8eSGreg Roach * A sentence describing what this module does. 653d8b2a8eSGreg Roach * 663d8b2a8eSGreg Roach * @return string 673d8b2a8eSGreg Roach */ 683d8b2a8eSGreg Roach public function description(): string 693d8b2a8eSGreg Roach { 703d8b2a8eSGreg Roach return I18N::translate('Theme') . ' — ' . $this->title(); 713d8b2a8eSGreg Roach } 723d8b2a8eSGreg Roach 733d8b2a8eSGreg Roach /** 74ade503dfSGreg Roach * Display an icon for this fact. 75ade503dfSGreg Roach * 76ade503dfSGreg Roach * @param Fact $fact 77ade503dfSGreg Roach * 78ade503dfSGreg Roach * @return string 79ade503dfSGreg Roach */ 80ade503dfSGreg Roach public function icon(Fact $fact): string 81ade503dfSGreg Roach { 82e837ff07SGreg Roach $asset = 'public/css/' . $this->name() . '/images/facts/' . $fact->getTag() . '.png'; 83f397d0fdSGreg Roach if (file_exists(Webtrees::ROOT_DIR . 'public' . $asset)) { 84e837ff07SGreg Roach return '<img src="' . e(asset($asset)) . '" title="' . GedcomTag::getLabel($fact->getTag()) . '">'; 85ade503dfSGreg Roach } 86ade503dfSGreg Roach 87ade503dfSGreg Roach // Spacer image - for alignment - until we move to a sprite. 88e837ff07SGreg Roach $asset = 'public/css/' . $this->name() . '/images/facts/NULL.png'; 89f397d0fdSGreg Roach if (file_exists(Webtrees::ROOT_DIR . 'public' . $asset)) { 90e837ff07SGreg Roach return '<img src="' . e(asset($asset)) . '">'; 91ade503dfSGreg Roach } 92ade503dfSGreg Roach 93ade503dfSGreg Roach return ''; 94ade503dfSGreg Roach } 95ade503dfSGreg Roach 96ade503dfSGreg Roach /** 97ade503dfSGreg Roach * Generate the facts, for display in charts. 98ade503dfSGreg Roach * 99ade503dfSGreg Roach * @param Individual $individual 100ade503dfSGreg Roach * 101ade503dfSGreg Roach * @return string 102ade503dfSGreg Roach */ 103ade503dfSGreg Roach public function individualBoxFacts(Individual $individual): string 104ade503dfSGreg Roach { 105ade503dfSGreg Roach $html = ''; 106ade503dfSGreg Roach 107ade503dfSGreg Roach $opt_tags = preg_split('/\W/', $individual->tree()->getPreference('CHART_BOX_TAGS'), 0, PREG_SPLIT_NO_EMPTY); 108ade503dfSGreg Roach // Show BIRT or equivalent event 109ade503dfSGreg Roach foreach (Gedcom::BIRTH_EVENTS as $birttag) { 11022d65e5aSGreg Roach if (!in_array($birttag, $opt_tags, true)) { 111820b62dfSGreg Roach $event = $individual->facts([$birttag])->first(); 112820b62dfSGreg Roach if ($event instanceof Fact) { 113ade503dfSGreg Roach $html .= $event->summary(); 114ade503dfSGreg Roach break; 115ade503dfSGreg Roach } 116ade503dfSGreg Roach } 117ade503dfSGreg Roach } 118ade503dfSGreg Roach // Show optional events (before death) 119ade503dfSGreg Roach foreach ($opt_tags as $key => $tag) { 12022d65e5aSGreg Roach if (!in_array($tag, Gedcom::DEATH_EVENTS, true)) { 121820b62dfSGreg Roach $event = $individual->facts([$tag])->first(); 122820b62dfSGreg Roach if ($event instanceof Fact) { 123ade503dfSGreg Roach $html .= $event->summary(); 124ade503dfSGreg Roach unset($opt_tags[$key]); 125ade503dfSGreg Roach } 126ade503dfSGreg Roach } 127ade503dfSGreg Roach } 128ade503dfSGreg Roach // Show DEAT or equivalent event 129ade503dfSGreg Roach foreach (Gedcom::DEATH_EVENTS as $deattag) { 130820b62dfSGreg Roach $event = $individual->facts([$deattag])->first(); 131820b62dfSGreg Roach if ($event instanceof Fact) { 132ade503dfSGreg Roach $html .= $event->summary(); 13322d65e5aSGreg Roach if (in_array($deattag, $opt_tags, true)) { 13422d65e5aSGreg Roach unset($opt_tags[array_search($deattag, $opt_tags, true)]); 135ade503dfSGreg Roach } 136ade503dfSGreg Roach break; 137ade503dfSGreg Roach } 138ade503dfSGreg Roach } 139ade503dfSGreg Roach // Show remaining optional events (after death) 140ade503dfSGreg Roach foreach ($opt_tags as $tag) { 141820b62dfSGreg Roach $event = $individual->facts([$tag])->first(); 142820b62dfSGreg Roach if ($event instanceof Fact) { 143ade503dfSGreg Roach $html .= $event->summary(); 144ade503dfSGreg Roach } 145ade503dfSGreg Roach } 146ade503dfSGreg Roach 147ade503dfSGreg Roach return $html; 148ade503dfSGreg Roach } 149ade503dfSGreg Roach 150ade503dfSGreg Roach /** 151ade503dfSGreg Roach * Links, to show in chart boxes; 152ade503dfSGreg Roach * 153ade503dfSGreg Roach * @param Individual $individual 154ade503dfSGreg Roach * 155ade503dfSGreg Roach * @return Menu[] 156ade503dfSGreg Roach */ 157ade503dfSGreg Roach public function individualBoxMenu(Individual $individual): array 158ade503dfSGreg Roach { 159ade503dfSGreg Roach $menus = array_merge( 160ade503dfSGreg Roach $this->individualBoxMenuCharts($individual), 161ade503dfSGreg Roach $this->individualBoxMenuFamilyLinks($individual) 162ade503dfSGreg Roach ); 163ade503dfSGreg Roach 164ade503dfSGreg Roach return $menus; 165ade503dfSGreg Roach } 166ade503dfSGreg Roach 167ade503dfSGreg Roach /** 168ade503dfSGreg Roach * Chart links, to show in chart boxes; 169ade503dfSGreg Roach * 170ade503dfSGreg Roach * @param Individual $individual 171ade503dfSGreg Roach * 172ade503dfSGreg Roach * @return Menu[] 173ade503dfSGreg Roach */ 174ade503dfSGreg Roach public function individualBoxMenuCharts(Individual $individual): array 175ade503dfSGreg Roach { 176ade503dfSGreg Roach $menus = []; 177f39638cfSGreg Roach foreach (app(ModuleService::class)->findByComponent(ModuleChartInterface::class, $individual->tree(), Auth::user()) as $chart) { 178ade503dfSGreg Roach $menu = $chart->chartBoxMenu($individual); 179ade503dfSGreg Roach if ($menu) { 180ade503dfSGreg Roach $menus[] = $menu; 181ade503dfSGreg Roach } 182ade503dfSGreg Roach } 183ade503dfSGreg Roach 1840b93976aSGreg Roach usort($menus, static function (Menu $x, Menu $y): int { 185ade503dfSGreg Roach return I18N::strcasecmp($x->getLabel(), $y->getLabel()); 186ade503dfSGreg Roach }); 187ade503dfSGreg Roach 188ade503dfSGreg Roach return $menus; 189ade503dfSGreg Roach } 190ade503dfSGreg Roach 191ade503dfSGreg Roach /** 192ade503dfSGreg Roach * Family links, to show in chart boxes. 193ade503dfSGreg Roach * 194ade503dfSGreg Roach * @param Individual $individual 195ade503dfSGreg Roach * 196ade503dfSGreg Roach * @return Menu[] 197ade503dfSGreg Roach */ 198ade503dfSGreg Roach public function individualBoxMenuFamilyLinks(Individual $individual): array 199ade503dfSGreg Roach { 200ade503dfSGreg Roach $menus = []; 201ade503dfSGreg Roach 20239ca88baSGreg Roach foreach ($individual->spouseFamilies() as $family) { 203ade503dfSGreg Roach $menus[] = new Menu('<strong>' . I18N::translate('Family with spouse') . '</strong>', $family->url()); 20439ca88baSGreg Roach $spouse = $family->spouse($individual); 205ade503dfSGreg Roach if ($spouse && $spouse->canShowName()) { 20639ca88baSGreg Roach $menus[] = new Menu($spouse->fullName(), $spouse->url()); 207ade503dfSGreg Roach } 20839ca88baSGreg Roach foreach ($family->children() as $child) { 209ade503dfSGreg Roach if ($child->canShowName()) { 21039ca88baSGreg Roach $menus[] = new Menu($child->fullName(), $child->url()); 211ade503dfSGreg Roach } 212ade503dfSGreg Roach } 213ade503dfSGreg Roach } 214ade503dfSGreg Roach 215ade503dfSGreg Roach return $menus; 216ade503dfSGreg Roach } 217ade503dfSGreg Roach 218ade503dfSGreg Roach /** 219f567c3d8SGreg Roach * Generate a menu item to change the blocks on the current tree/user page. 220ade503dfSGreg Roach * 2210c8c69d4SGreg Roach * @param Tree $tree 2220c8c69d4SGreg Roach * 223ade503dfSGreg Roach * @return Menu|null 224ade503dfSGreg Roach */ 225e364afe4SGreg Roach public function menuChangeBlocks(Tree $tree): ?Menu 226ade503dfSGreg Roach { 227eb235819SGreg Roach /** @var ServerRequestInterface $request */ 2286ccdf4f0SGreg Roach $request = app(ServerRequestInterface::class); 229e6bcfa02SGreg Roach 2300d7461faSGreg Roach $route = $request->getAttribute('route'); 231eb235819SGreg Roach 232eb235819SGreg Roach if (Auth::check() && $route === 'user-page') { 233d72b284aSGreg Roach return new Menu(I18N::translate('Customize this page'), route('user-page-edit', ['tree' => $tree->name()]), 'menu-change-blocks'); 234ade503dfSGreg Roach } 235ade503dfSGreg Roach 236eb235819SGreg Roach if (Auth::isManager($tree) && $route === 'tree-page') { 237d72b284aSGreg Roach return new Menu(I18N::translate('Customize this page'), route('tree-page-edit', ['tree' => $tree->name()]), 'menu-change-blocks'); 238ade503dfSGreg Roach } 239ade503dfSGreg Roach 240ade503dfSGreg Roach return null; 241ade503dfSGreg Roach } 242ade503dfSGreg Roach 243ade503dfSGreg Roach /** 244ade503dfSGreg Roach * Generate a menu item for the control panel. 245ade503dfSGreg Roach * 2460c8c69d4SGreg Roach * @param Tree $tree 2470c8c69d4SGreg Roach * 248ade503dfSGreg Roach * @return Menu|null 249ade503dfSGreg Roach */ 250e364afe4SGreg Roach public function menuControlPanel(Tree $tree): ?Menu 251ade503dfSGreg Roach { 252ade503dfSGreg Roach if (Auth::isAdmin()) { 2530c0910bfSGreg Roach return new Menu(I18N::translate('Control panel'), route(ControlPanel::class), 'menu-admin'); 254ade503dfSGreg Roach } 255ade503dfSGreg Roach 2560c8c69d4SGreg Roach if (Auth::isManager($tree)) { 2570c0910bfSGreg Roach return new Menu(I18N::translate('Control panel'), route('manage-trees'), 'menu-admin'); 258ade503dfSGreg Roach } 259ade503dfSGreg Roach 260ade503dfSGreg Roach return null; 261ade503dfSGreg Roach } 262ade503dfSGreg Roach 263ade503dfSGreg Roach /** 264ade503dfSGreg Roach * A menu to show a list of available languages. 265ade503dfSGreg Roach * 266ade503dfSGreg Roach * @return Menu|null 267ade503dfSGreg Roach */ 268e364afe4SGreg Roach public function menuLanguages(): ?Menu 269ade503dfSGreg Roach { 27090a2f718SGreg Roach $locale = app(ServerRequestInterface::class)->getAttribute('locale'); 27190a2f718SGreg Roach assert($locale instanceof LocaleInterface); 27290a2f718SGreg Roach 273ade503dfSGreg Roach $menu = new Menu(I18N::translate('Language'), '#', 'menu-language'); 274ade503dfSGreg Roach 27590a2f718SGreg Roach foreach (I18N::activeLocales() as $active_locale) { 27690a2f718SGreg Roach $language_tag = $active_locale->languageTag(); 27790a2f718SGreg Roach $class = 'menu-language-' . $language_tag . ($locale->languageTag() === $language_tag ? ' active' : ''); 27890a2f718SGreg Roach $menu->addSubmenu(new Menu($active_locale->endonym(), '#', $class, [ 2797adfb8e5SGreg Roach 'data-post-url' => route(SelectLanguage::class, ['language' => $language_tag]), 280ade503dfSGreg Roach ])); 281ade503dfSGreg Roach } 282ade503dfSGreg Roach 283ade503dfSGreg Roach if (count($menu->getSubmenus()) > 1) { 284ade503dfSGreg Roach return $menu; 285ade503dfSGreg Roach } 286ade503dfSGreg Roach 287ade503dfSGreg Roach return null; 288ade503dfSGreg Roach } 289ade503dfSGreg Roach 290ade503dfSGreg Roach /** 291ade503dfSGreg Roach * A login menu option (or null if we are already logged in). 292ade503dfSGreg Roach * 293ade503dfSGreg Roach * @return Menu|null 294ade503dfSGreg Roach */ 295e364afe4SGreg Roach public function menuLogin(): ?Menu 296ade503dfSGreg Roach { 297ade503dfSGreg Roach if (Auth::check()) { 298ade503dfSGreg Roach return null; 299ade503dfSGreg Roach } 300ade503dfSGreg Roach 30186661454SGreg Roach $request = app(ServerRequestInterface::class); 30286661454SGreg Roach 303ade503dfSGreg Roach // Return to this page after login... 304b6c0b825SGreg Roach $redirect = $request->getQueryParams()['url'] ?? (string) $request->getUri(); 305ade503dfSGreg Roach 306ade503dfSGreg Roach // ...but switch from the tree-page to the user-page 30791c514e5SGreg Roach if ($request->getAttribute('route') === 'tree-page') { 30891c514e5SGreg Roach $tree = $request->getAttribute('tree'); 30975964c75SGreg Roach assert($tree instanceof Tree); 31091c514e5SGreg Roach $redirect = route('user-page', ['tree' => $tree->name()]); 31191c514e5SGreg Roach } 312ade503dfSGreg Roach 31386661454SGreg Roach // Stay on the same tree page 31486661454SGreg Roach $tree = $request->getAttribute('tree'); 31591c514e5SGreg Roach $url = route(LoginPage::class, ['tree' => $tree instanceof Tree ? $tree->name() : null, 'url' => $redirect]); 31686661454SGreg Roach 31786661454SGreg Roach return new Menu(I18N::translate('Sign in'), $url, 'menu-login', ['rel' => 'nofollow']); 318ade503dfSGreg Roach } 319ade503dfSGreg Roach 320ade503dfSGreg Roach /** 321ade503dfSGreg Roach * A logout menu option (or null if we are already logged out). 322ade503dfSGreg Roach * 323ade503dfSGreg Roach * @return Menu|null 324ade503dfSGreg Roach */ 325e364afe4SGreg Roach public function menuLogout(): ?Menu 326ade503dfSGreg Roach { 327ade503dfSGreg Roach if (Auth::check()) { 3289b541e4aSGreg Roach $parameters = [ 3299b541e4aSGreg Roach 'data-post-url' => route(Logout::class), 3309b541e4aSGreg Roach ]; 3319b541e4aSGreg Roach 3329b541e4aSGreg Roach return new Menu(I18N::translate('Sign out'), '#', 'menu-logout', $parameters); 333ade503dfSGreg Roach } 334ade503dfSGreg Roach 335ade503dfSGreg Roach return null; 336ade503dfSGreg Roach } 337ade503dfSGreg Roach 338ade503dfSGreg Roach /** 339ade503dfSGreg Roach * A link to allow users to edit their account settings. 340ade503dfSGreg Roach * 34165aec466SGreg Roach * @param Tree|null $tree 342a49d0e3fSGreg Roach * 343a49d0e3fSGreg Roach * @return Menu 344ade503dfSGreg Roach */ 345a49d0e3fSGreg Roach public function menuMyAccount(?Tree $tree): Menu 346ade503dfSGreg Roach { 347a49d0e3fSGreg Roach $url = route(AccountEdit::class, ['tree' => $tree instanceof Tree ? $tree->name() : null]); 348ade503dfSGreg Roach 349a49d0e3fSGreg Roach return new Menu(I18N::translate('My account'), $url); 350ade503dfSGreg Roach } 351ade503dfSGreg Roach 352ade503dfSGreg Roach /** 353ade503dfSGreg Roach * A link to the user's individual record (individual.php). 354ade503dfSGreg Roach * 3550c8c69d4SGreg Roach * @param Tree $tree 3560c8c69d4SGreg Roach * 357ade503dfSGreg Roach * @return Menu|null 358ade503dfSGreg Roach */ 359e364afe4SGreg Roach public function menuMyIndividualRecord(Tree $tree): ?Menu 360ade503dfSGreg Roach { 361*7c4add84SGreg Roach $record = Individual::getInstance($tree->getUserPreference(Auth::user(), User::PREF_TREE_ACCOUNT_XREF), $tree); 362ade503dfSGreg Roach 363ade503dfSGreg Roach if ($record) { 364ade503dfSGreg Roach return new Menu(I18N::translate('My individual record'), $record->url(), 'menu-myrecord'); 365ade503dfSGreg Roach } 366ade503dfSGreg Roach 367ade503dfSGreg Roach return null; 368ade503dfSGreg Roach } 369ade503dfSGreg Roach 370ade503dfSGreg Roach /** 371ade503dfSGreg Roach * A link to the user's personal home page. 372ade503dfSGreg Roach * 3730c8c69d4SGreg Roach * @param Tree $tree 3740c8c69d4SGreg Roach * 375ade503dfSGreg Roach * @return Menu 376ade503dfSGreg Roach */ 3770c8c69d4SGreg Roach public function menuMyPage(Tree $tree): Menu 378ade503dfSGreg Roach { 379d72b284aSGreg Roach return new Menu(I18N::translate('My page'), route('user-page', ['tree' => $tree->name()]), 'menu-mypage'); 380ade503dfSGreg Roach } 381ade503dfSGreg Roach 382ade503dfSGreg Roach /** 383ade503dfSGreg Roach * A menu for the user's personal pages. 384ade503dfSGreg Roach * 3850c8c69d4SGreg Roach * @param Tree|null $tree 3860c8c69d4SGreg Roach * 387ade503dfSGreg Roach * @return Menu|null 388ade503dfSGreg Roach */ 389e364afe4SGreg Roach public function menuMyPages(?Tree $tree): ?Menu 390ade503dfSGreg Roach { 391a49d0e3fSGreg Roach if (Auth::id()) { 392a49d0e3fSGreg Roach if ($tree instanceof Tree) { 393ade503dfSGreg Roach return new Menu(I18N::translate('My pages'), '#', 'menu-mymenu', [], array_filter([ 3940c8c69d4SGreg Roach $this->menuMyPage($tree), 3950c8c69d4SGreg Roach $this->menuMyIndividualRecord($tree), 3960c8c69d4SGreg Roach $this->menuMyPedigree($tree), 397a49d0e3fSGreg Roach $this->menuMyAccount($tree), 3980c8c69d4SGreg Roach $this->menuControlPanel($tree), 3990c8c69d4SGreg Roach $this->menuChangeBlocks($tree), 400ade503dfSGreg Roach ])); 401ade503dfSGreg Roach } 402ade503dfSGreg Roach 403a49d0e3fSGreg Roach return $this->menuMyAccount($tree); 404a49d0e3fSGreg Roach } 405a49d0e3fSGreg Roach 406ade503dfSGreg Roach return null; 407ade503dfSGreg Roach } 408ade503dfSGreg Roach 409ade503dfSGreg Roach /** 410ade503dfSGreg Roach * A link to the user's individual record. 411ade503dfSGreg Roach * 4120c8c69d4SGreg Roach * @param Tree $tree 4130c8c69d4SGreg Roach * 414ade503dfSGreg Roach * @return Menu|null 415ade503dfSGreg Roach */ 416e364afe4SGreg Roach public function menuMyPedigree(Tree $tree): ?Menu 417ade503dfSGreg Roach { 418*7c4add84SGreg Roach $gedcomid = $tree->getUserPreference(Auth::user(), User::PREF_TREE_ACCOUNT_XREF); 419ade503dfSGreg Roach 4200c8c69d4SGreg Roach $pedigree_chart = app(ModuleService::class)->findByComponent(ModuleChartInterface::class, $tree, Auth::user()) 4210b5fd0a6SGreg Roach ->filter(static function (ModuleInterface $module): bool { 422ade503dfSGreg Roach return $module instanceof PedigreeChartModule; 423ade503dfSGreg Roach }); 424ade503dfSGreg Roach 425ade503dfSGreg Roach if ($gedcomid !== '' && $pedigree_chart instanceof PedigreeChartModule) { 426ade503dfSGreg Roach return new Menu( 427ade503dfSGreg Roach I18N::translate('My pedigree'), 428ade503dfSGreg Roach route('pedigree', [ 429ade503dfSGreg Roach 'xref' => $gedcomid, 4309022ab66SGreg Roach 'tree' => $tree->name(), 431ade503dfSGreg Roach ]), 432ade503dfSGreg Roach 'menu-mypedigree' 433ade503dfSGreg Roach ); 434ade503dfSGreg Roach } 435ade503dfSGreg Roach 436ade503dfSGreg Roach return null; 437ade503dfSGreg Roach } 438ade503dfSGreg Roach 439ade503dfSGreg Roach /** 440ade503dfSGreg Roach * Create a pending changes menu. 441ade503dfSGreg Roach * 4420c8c69d4SGreg Roach * @param Tree|null $tree 4430c8c69d4SGreg Roach * 444ade503dfSGreg Roach * @return Menu|null 445ade503dfSGreg Roach */ 446e364afe4SGreg Roach public function menuPendingChanges(?Tree $tree): ?Menu 447ade503dfSGreg Roach { 4480c8c69d4SGreg Roach if ($tree instanceof Tree && $tree->hasPendingEdit() && Auth::isModerator($tree)) { 44922e73debSGreg Roach $url = route(PendingChanges::class, [ 4509022ab66SGreg Roach 'tree' => $tree->name(), 451cf8c0692SGreg Roach 'url' => (string) app(ServerRequestInterface::class)->getUri(), 452ade503dfSGreg Roach ]); 453ade503dfSGreg Roach 454ade503dfSGreg Roach return new Menu(I18N::translate('Pending changes'), $url, 'menu-pending'); 455ade503dfSGreg Roach } 456ade503dfSGreg Roach 457ade503dfSGreg Roach return null; 458ade503dfSGreg Roach } 459ade503dfSGreg Roach 460ade503dfSGreg Roach /** 461ade503dfSGreg Roach * Themes menu. 462ade503dfSGreg Roach * 463ade503dfSGreg Roach * @return Menu|null 464ade503dfSGreg Roach */ 465e364afe4SGreg Roach public function menuThemes(): ?Menu 466ade503dfSGreg Roach { 467b668782fSGreg Roach $themes = app(ModuleService::class)->findByInterface(ModuleThemeInterface::class, false, true); 468df8baf00SGreg Roach 469cab242e7SGreg Roach $current_theme = app(ModuleThemeInterface::class); 4708136679eSGreg Roach 4718136679eSGreg Roach if ($themes->count() > 1) { 4720b5fd0a6SGreg Roach $submenus = $themes->map(static function (ModuleThemeInterface $theme) use ($current_theme): Menu { 4738136679eSGreg Roach $active = $theme->name() === $current_theme->name(); 4748136679eSGreg Roach $class = 'menu-theme-' . $theme->name() . ($active ? ' active' : ''); 4758136679eSGreg Roach 4768136679eSGreg Roach return new Menu($theme->title(), '#', $class, [ 4777adfb8e5SGreg Roach 'data-post-url' => route(SelectTheme::class, ['theme' => $theme->name()]), 478ade503dfSGreg Roach ]); 479ade503dfSGreg Roach }); 480ade503dfSGreg Roach 4818136679eSGreg Roach return new Menu(I18N::translate('Theme'), '#', 'menu-theme', [], $submenus->all()); 482ade503dfSGreg Roach } 483ade503dfSGreg Roach 484ade503dfSGreg Roach return null; 485ade503dfSGreg Roach } 486ade503dfSGreg Roach 487ade503dfSGreg Roach /** 488ade503dfSGreg Roach * Misecellaneous dimensions, fonts, styles, etc. 489ade503dfSGreg Roach * 490ade503dfSGreg Roach * @param string $parameter_name 491ade503dfSGreg Roach * 492ade503dfSGreg Roach * @return string|int|float 493ade503dfSGreg Roach */ 494ade503dfSGreg Roach public function parameter($parameter_name) 495ade503dfSGreg Roach { 496ade503dfSGreg Roach return ''; 497ade503dfSGreg Roach } 498ade503dfSGreg Roach 499ade503dfSGreg Roach /** 500ade503dfSGreg Roach * Generate a list of items for the main menu. 501ade503dfSGreg Roach * 5020c8c69d4SGreg Roach * @param Tree|null $tree 5030c8c69d4SGreg Roach * 504ade503dfSGreg Roach * @return Menu[] 505ade503dfSGreg Roach */ 5060c8c69d4SGreg Roach public function genealogyMenu(?Tree $tree): array 507ade503dfSGreg Roach { 5080c8c69d4SGreg Roach if ($tree === null) { 5090c8c69d4SGreg Roach return []; 5100c8c69d4SGreg Roach } 5110c8c69d4SGreg Roach 5120c8c69d4SGreg Roach return app(ModuleService::class)->findByComponent(ModuleMenuInterface::class, $tree, Auth::user()) 5130b5fd0a6SGreg Roach ->map(static function (ModuleMenuInterface $menu) use ($tree): ?Menu { 5140c8c69d4SGreg Roach return $menu->getMenu($tree); 515ade503dfSGreg Roach }) 516ade503dfSGreg Roach ->filter() 517ade503dfSGreg Roach ->all(); 518ade503dfSGreg Roach } 519ade503dfSGreg Roach 520ade503dfSGreg Roach /** 5210c8c69d4SGreg Roach * Create the genealogy menu. 522ade503dfSGreg Roach * 523ade503dfSGreg Roach * @param Menu[] $menus 524ade503dfSGreg Roach * 525ade503dfSGreg Roach * @return string 526ade503dfSGreg Roach */ 5270c8c69d4SGreg Roach public function genealogyMenuContent(array $menus): string 528ade503dfSGreg Roach { 5290b5fd0a6SGreg Roach return implode('', array_map(static function (Menu $menu): string { 530ade503dfSGreg Roach return $menu->bootstrap4(); 531ade503dfSGreg Roach }, $menus)); 532ade503dfSGreg Roach } 533ade503dfSGreg Roach 534ade503dfSGreg Roach /** 535ade503dfSGreg Roach * Generate a list of items for the user menu. 536ade503dfSGreg Roach * 5370c8c69d4SGreg Roach * @param Tree|null $tree 5380c8c69d4SGreg Roach * 539ade503dfSGreg Roach * @return Menu[] 540ade503dfSGreg Roach */ 5410c8c69d4SGreg Roach public function userMenu(?Tree $tree): array 542ade503dfSGreg Roach { 543ade503dfSGreg Roach return array_filter([ 5440c8c69d4SGreg Roach $this->menuPendingChanges($tree), 5450c8c69d4SGreg Roach $this->menuMyPages($tree), 546ade503dfSGreg Roach $this->menuThemes(), 547ade503dfSGreg Roach $this->menuLanguages(), 548ade503dfSGreg Roach $this->menuLogin(), 549ade503dfSGreg Roach $this->menuLogout(), 550ade503dfSGreg Roach ]); 551ade503dfSGreg Roach } 552ade503dfSGreg Roach 553ade503dfSGreg Roach /** 554ade503dfSGreg Roach * A list of CSS files to include for this page. 555ade503dfSGreg Roach * 556ade503dfSGreg Roach * @return string[] 557ade503dfSGreg Roach */ 558ade503dfSGreg Roach public function stylesheets(): array 559ade503dfSGreg Roach { 560ade503dfSGreg Roach return []; 561ade503dfSGreg Roach } 56249a243cbSGreg Roach} 563