149a243cbSGreg Roach<?php 249a243cbSGreg Roach/** 349a243cbSGreg Roach * webtrees: online genealogy 449a243cbSGreg Roach * Copyright (C) 2019 webtrees development team 549a243cbSGreg Roach * This program is free software: you can redistribute it and/or modify 649a243cbSGreg Roach * it under the terms of the GNU General Public License as published by 749a243cbSGreg Roach * the Free Software Foundation, either version 3 of the License, or 849a243cbSGreg Roach * (at your option) any later version. 949a243cbSGreg Roach * This program is distributed in the hope that it will be useful, 1049a243cbSGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 1149a243cbSGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1249a243cbSGreg Roach * GNU General Public License for more details. 1349a243cbSGreg Roach * You should have received a copy of the GNU General Public License 1449a243cbSGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 1549a243cbSGreg Roach */ 1649a243cbSGreg Roachdeclare(strict_types=1); 1749a243cbSGreg Roach 1849a243cbSGreg Roachnamespace Fisharebest\Webtrees\Module; 1949a243cbSGreg Roach 20ade503dfSGreg Roachuse Fisharebest\Webtrees\Auth; 21ade503dfSGreg Roachuse Fisharebest\Webtrees\Fact; 22ade503dfSGreg Roachuse Fisharebest\Webtrees\Gedcom; 23ade503dfSGreg Roachuse Fisharebest\Webtrees\GedcomTag; 24ade503dfSGreg Roachuse Fisharebest\Webtrees\I18N; 25ade503dfSGreg Roachuse Fisharebest\Webtrees\Individual; 26ade503dfSGreg Roachuse Fisharebest\Webtrees\Menu; 274ca7e03cSGreg Roachuse Fisharebest\Webtrees\Services\ModuleService; 28ade503dfSGreg Roachuse Fisharebest\Webtrees\Tree; 29ade503dfSGreg Roachuse Symfony\Component\HttpFoundation\Request; 30ade503dfSGreg Roach 3149a243cbSGreg Roach/** 3249a243cbSGreg Roach * Trait ModuleThemeTrait - default implementation of ModuleThemeInterface 3349a243cbSGreg Roach */ 3449a243cbSGreg Roachtrait ModuleThemeTrait 3549a243cbSGreg Roach{ 36ade503dfSGreg Roach /** @var Request */ 37ade503dfSGreg Roach protected $request; 38ade503dfSGreg Roach 39ade503dfSGreg Roach /** @var Tree|null */ 40ade503dfSGreg Roach protected $tree; 41ade503dfSGreg Roach 42ade503dfSGreg Roach /** 43ade503dfSGreg Roach * @param Request $request 44ade503dfSGreg Roach * @param Tree|null $tree The current tree (if there is one). 45ade503dfSGreg Roach */ 46ade503dfSGreg Roach public function __construct(Request $request, ?Tree $tree) 47ade503dfSGreg Roach { 48ade503dfSGreg Roach $this->request = $request; 49ade503dfSGreg Roach $this->tree = $tree; 50ade503dfSGreg Roach } 51ade503dfSGreg Roach 52ade503dfSGreg Roach /** 53ade503dfSGreg Roach * Add markup to the secondary menu. 54ade503dfSGreg Roach * 55ade503dfSGreg Roach * @return string 56ade503dfSGreg Roach */ 57ade503dfSGreg Roach public function formatSecondaryMenu(): string 58ade503dfSGreg Roach { 59ade503dfSGreg Roach return 60ade503dfSGreg Roach '<ul class="nav wt-secondary-menu">' . 61ade503dfSGreg Roach implode('', array_map(function (Menu $menu): string { 62ade503dfSGreg Roach return $this->formatSecondaryMenuItem($menu); 63ade503dfSGreg Roach }, $this->secondaryMenu())) . 64ade503dfSGreg Roach '</ul>'; 65ade503dfSGreg Roach } 66ade503dfSGreg Roach 67ade503dfSGreg Roach /** 68ade503dfSGreg Roach * Add markup to an item in the secondary menu. 69ade503dfSGreg Roach * 70ade503dfSGreg Roach * @param Menu $menu 71ade503dfSGreg Roach * 72ade503dfSGreg Roach * @return string 73ade503dfSGreg Roach */ 74ade503dfSGreg Roach public function formatSecondaryMenuItem(Menu $menu): string 75ade503dfSGreg Roach { 76ade503dfSGreg Roach return $menu->bootstrap4(); 77ade503dfSGreg Roach } 78ade503dfSGreg Roach 79ade503dfSGreg Roach /** 80ade503dfSGreg Roach * Display an icon for this fact. 81ade503dfSGreg Roach * 82e837ff07SGreg Roach * @TODO use CSS for this 83e837ff07SGreg Roach * 84ade503dfSGreg Roach * @param Fact $fact 85ade503dfSGreg Roach * 86ade503dfSGreg Roach * @return string 87ade503dfSGreg Roach */ 88ade503dfSGreg Roach public function icon(Fact $fact): string 89ade503dfSGreg Roach { 90e837ff07SGreg Roach $asset = 'public/css/' . $this->name() . '/images/facts/' . $fact->getTag() . '.png'; 91e837ff07SGreg Roach if (file_exists(WT_ROOT . 'public' . $asset)) { 92e837ff07SGreg Roach return '<img src="' . e(asset($asset)) . '" title="' . GedcomTag::getLabel($fact->getTag()) . '">'; 93ade503dfSGreg Roach } 94ade503dfSGreg Roach 95ade503dfSGreg Roach // Spacer image - for alignment - until we move to a sprite. 96e837ff07SGreg Roach $asset = 'public/css/' . $this->name() . '/images/facts/NULL.png'; 97e837ff07SGreg Roach if (file_exists(WT_ROOT . 'public' . $asset)) { 98e837ff07SGreg Roach return '<img src="' . e(asset($asset)) . '">'; 99ade503dfSGreg Roach } 100ade503dfSGreg Roach 101ade503dfSGreg Roach return ''; 102ade503dfSGreg Roach } 103ade503dfSGreg Roach 104ade503dfSGreg Roach /** 105ade503dfSGreg Roach * Display an individual in a box - for charts, etc. 106ade503dfSGreg Roach * 107ade503dfSGreg Roach * @param Individual $individual 108ade503dfSGreg Roach * 109ade503dfSGreg Roach * @return string 110ade503dfSGreg Roach */ 111ade503dfSGreg Roach public function individualBox(Individual $individual): string 112ade503dfSGreg Roach { 113*242a7862SGreg Roach return view('chart-box', ['individual' => $individual]); 114ade503dfSGreg Roach } 115ade503dfSGreg Roach 116ade503dfSGreg Roach /** 117ade503dfSGreg Roach * Display an empty box - for a missing individual in a chart. 118ade503dfSGreg Roach * 119ade503dfSGreg Roach * @return string 120ade503dfSGreg Roach */ 121ade503dfSGreg Roach public function individualBoxEmpty(): string 122ade503dfSGreg Roach { 123*242a7862SGreg Roach return '<div class="wt-chart-box"></div>'; 124ade503dfSGreg Roach } 125ade503dfSGreg Roach 126ade503dfSGreg Roach /** 127ade503dfSGreg Roach * Display an individual in a box - for charts, etc. 128ade503dfSGreg Roach * 129ade503dfSGreg Roach * @param Individual $individual 130ade503dfSGreg Roach * 131ade503dfSGreg Roach * @return string 132ade503dfSGreg Roach */ 133ade503dfSGreg Roach public function individualBoxLarge(Individual $individual): string 134ade503dfSGreg Roach { 135*242a7862SGreg Roach return $this->individualBox($individual); 136ade503dfSGreg Roach } 137ade503dfSGreg Roach 138ade503dfSGreg Roach /** 139ade503dfSGreg Roach * Display an individual in a box - for charts, etc. 140ade503dfSGreg Roach * 141ade503dfSGreg Roach * @param Individual $individual 142ade503dfSGreg Roach * 143ade503dfSGreg Roach * @return string 144ade503dfSGreg Roach */ 145ade503dfSGreg Roach public function individualBoxSmall(Individual $individual): string 146ade503dfSGreg Roach { 147*242a7862SGreg Roach return $this->individualBox($individual); 148ade503dfSGreg Roach } 149ade503dfSGreg Roach 150ade503dfSGreg Roach /** 151ade503dfSGreg Roach * Display an individual in a box - for charts, etc. 152ade503dfSGreg Roach * 153ade503dfSGreg Roach * @return string 154ade503dfSGreg Roach */ 155ade503dfSGreg Roach public function individualBoxSmallEmpty(): string 156ade503dfSGreg Roach { 157*242a7862SGreg Roach return '<div class="wt-chart-box"></div>'; 158ade503dfSGreg Roach } 159ade503dfSGreg Roach 160ade503dfSGreg Roach /** 161ade503dfSGreg Roach * Generate the facts, for display in charts. 162ade503dfSGreg Roach * 163ade503dfSGreg Roach * @param Individual $individual 164ade503dfSGreg Roach * 165ade503dfSGreg Roach * @return string 166ade503dfSGreg Roach */ 167ade503dfSGreg Roach public function individualBoxFacts(Individual $individual): string 168ade503dfSGreg Roach { 169ade503dfSGreg Roach $html = ''; 170ade503dfSGreg Roach 171ade503dfSGreg Roach $opt_tags = preg_split('/\W/', $individual->tree()->getPreference('CHART_BOX_TAGS'), 0, PREG_SPLIT_NO_EMPTY); 172ade503dfSGreg Roach // Show BIRT or equivalent event 173ade503dfSGreg Roach foreach (Gedcom::BIRTH_EVENTS as $birttag) { 174ade503dfSGreg Roach if (!in_array($birttag, $opt_tags)) { 175ade503dfSGreg Roach $event = $individual->getFirstFact($birttag); 176ade503dfSGreg Roach if ($event) { 177ade503dfSGreg Roach $html .= $event->summary(); 178ade503dfSGreg Roach break; 179ade503dfSGreg Roach } 180ade503dfSGreg Roach } 181ade503dfSGreg Roach } 182ade503dfSGreg Roach // Show optional events (before death) 183ade503dfSGreg Roach foreach ($opt_tags as $key => $tag) { 184ade503dfSGreg Roach if (!in_array($tag, Gedcom::DEATH_EVENTS)) { 185ade503dfSGreg Roach $event = $individual->getFirstFact($tag); 186ade503dfSGreg Roach if ($event !== null) { 187ade503dfSGreg Roach $html .= $event->summary(); 188ade503dfSGreg Roach unset($opt_tags[$key]); 189ade503dfSGreg Roach } 190ade503dfSGreg Roach } 191ade503dfSGreg Roach } 192ade503dfSGreg Roach // Show DEAT or equivalent event 193ade503dfSGreg Roach foreach (Gedcom::DEATH_EVENTS as $deattag) { 194ade503dfSGreg Roach $event = $individual->getFirstFact($deattag); 195ade503dfSGreg Roach if ($event) { 196ade503dfSGreg Roach $html .= $event->summary(); 197ade503dfSGreg Roach if (in_array($deattag, $opt_tags)) { 198ade503dfSGreg Roach unset($opt_tags[array_search($deattag, $opt_tags)]); 199ade503dfSGreg Roach } 200ade503dfSGreg Roach break; 201ade503dfSGreg Roach } 202ade503dfSGreg Roach } 203ade503dfSGreg Roach // Show remaining optional events (after death) 204ade503dfSGreg Roach foreach ($opt_tags as $tag) { 205ade503dfSGreg Roach $event = $individual->getFirstFact($tag); 206ade503dfSGreg Roach if ($event) { 207ade503dfSGreg Roach $html .= $event->summary(); 208ade503dfSGreg Roach } 209ade503dfSGreg Roach } 210ade503dfSGreg Roach 211ade503dfSGreg Roach return $html; 212ade503dfSGreg Roach } 213ade503dfSGreg Roach 214ade503dfSGreg Roach /** 215ade503dfSGreg Roach * Links, to show in chart boxes; 216ade503dfSGreg Roach * 217ade503dfSGreg Roach * @param Individual $individual 218ade503dfSGreg Roach * 219ade503dfSGreg Roach * @return Menu[] 220ade503dfSGreg Roach */ 221ade503dfSGreg Roach public function individualBoxMenu(Individual $individual): array 222ade503dfSGreg Roach { 223ade503dfSGreg Roach $menus = array_merge( 224ade503dfSGreg Roach $this->individualBoxMenuCharts($individual), 225ade503dfSGreg Roach $this->individualBoxMenuFamilyLinks($individual) 226ade503dfSGreg Roach ); 227ade503dfSGreg Roach 228ade503dfSGreg Roach return $menus; 229ade503dfSGreg Roach } 230ade503dfSGreg Roach 231ade503dfSGreg Roach /** 232ade503dfSGreg Roach * Chart links, to show in chart boxes; 233ade503dfSGreg Roach * 234ade503dfSGreg Roach * @param Individual $individual 235ade503dfSGreg Roach * 236ade503dfSGreg Roach * @return Menu[] 237ade503dfSGreg Roach */ 238ade503dfSGreg Roach public function individualBoxMenuCharts(Individual $individual): array 239ade503dfSGreg Roach { 240ade503dfSGreg Roach $menus = []; 2414ca7e03cSGreg Roach foreach (app(ModuleService::class)->findByComponent('chart', $this->tree, Auth::user()) as $chart) { 242ade503dfSGreg Roach $menu = $chart->chartBoxMenu($individual); 243ade503dfSGreg Roach if ($menu) { 244ade503dfSGreg Roach $menus[] = $menu; 245ade503dfSGreg Roach } 246ade503dfSGreg Roach } 247ade503dfSGreg Roach 248ade503dfSGreg Roach usort($menus, function (Menu $x, Menu $y) { 249ade503dfSGreg Roach return I18N::strcasecmp($x->getLabel(), $y->getLabel()); 250ade503dfSGreg Roach }); 251ade503dfSGreg Roach 252ade503dfSGreg Roach return $menus; 253ade503dfSGreg Roach } 254ade503dfSGreg Roach 255ade503dfSGreg Roach /** 256ade503dfSGreg Roach * Family links, to show in chart boxes. 257ade503dfSGreg Roach * 258ade503dfSGreg Roach * @param Individual $individual 259ade503dfSGreg Roach * 260ade503dfSGreg Roach * @return Menu[] 261ade503dfSGreg Roach */ 262ade503dfSGreg Roach public function individualBoxMenuFamilyLinks(Individual $individual): array 263ade503dfSGreg Roach { 264ade503dfSGreg Roach $menus = []; 265ade503dfSGreg Roach 266ade503dfSGreg Roach foreach ($individual->getSpouseFamilies() as $family) { 267ade503dfSGreg Roach $menus[] = new Menu('<strong>' . I18N::translate('Family with spouse') . '</strong>', $family->url()); 268ade503dfSGreg Roach $spouse = $family->getSpouse($individual); 269ade503dfSGreg Roach if ($spouse && $spouse->canShowName()) { 270ade503dfSGreg Roach $menus[] = new Menu($spouse->getFullName(), $spouse->url()); 271ade503dfSGreg Roach } 272ade503dfSGreg Roach foreach ($family->getChildren() as $child) { 273ade503dfSGreg Roach if ($child->canShowName()) { 274ade503dfSGreg Roach $menus[] = new Menu($child->getFullName(), $child->url()); 275ade503dfSGreg Roach } 276ade503dfSGreg Roach } 277ade503dfSGreg Roach } 278ade503dfSGreg Roach 279ade503dfSGreg Roach return $menus; 280ade503dfSGreg Roach } 281ade503dfSGreg Roach 282ade503dfSGreg Roach /** 283ade503dfSGreg Roach * Generate a menu item to change the blocks on the current (index.php) page. 284ade503dfSGreg Roach * 285ade503dfSGreg Roach * @return Menu|null 286ade503dfSGreg Roach */ 287ade503dfSGreg Roach public function menuChangeBlocks() 288ade503dfSGreg Roach { 289ade503dfSGreg Roach if (Auth::check() && $this->request->get('route') === 'user-page') { 290ade503dfSGreg Roach return new Menu(I18N::translate('Customize this page'), route('user-page-edit', ['ged' => $this->tree->name()]), 'menu-change-blocks'); 291ade503dfSGreg Roach } 292ade503dfSGreg Roach 293ade503dfSGreg Roach if (Auth::isManager($this->tree) && $this->request->get('route') === 'tree-page') { 294ade503dfSGreg Roach return new Menu(I18N::translate('Customize this page'), route('tree-page-edit', ['ged' => $this->tree->name()]), 'menu-change-blocks'); 295ade503dfSGreg Roach } 296ade503dfSGreg Roach 297ade503dfSGreg Roach return null; 298ade503dfSGreg Roach } 299ade503dfSGreg Roach 300ade503dfSGreg Roach /** 301ade503dfSGreg Roach * Generate a menu item for the control panel. 302ade503dfSGreg Roach * 303ade503dfSGreg Roach * @return Menu|null 304ade503dfSGreg Roach */ 305ade503dfSGreg Roach public function menuControlPanel() 306ade503dfSGreg Roach { 307ade503dfSGreg Roach if (Auth::isAdmin()) { 308ade503dfSGreg Roach return new Menu(I18N::translate('Control panel'), route('admin-control-panel'), 'menu-admin'); 309ade503dfSGreg Roach } 310ade503dfSGreg Roach 311ade503dfSGreg Roach if (Auth::isManager($this->tree)) { 312ade503dfSGreg Roach return new Menu(I18N::translate('Control panel'), route('admin-control-panel-manager'), 'menu-admin'); 313ade503dfSGreg Roach } 314ade503dfSGreg Roach 315ade503dfSGreg Roach return null; 316ade503dfSGreg Roach } 317ade503dfSGreg Roach 318ade503dfSGreg Roach /** 319ade503dfSGreg Roach * A menu to show a list of available languages. 320ade503dfSGreg Roach * 321ade503dfSGreg Roach * @return Menu|null 322ade503dfSGreg Roach */ 323ade503dfSGreg Roach public function menuLanguages() 324ade503dfSGreg Roach { 325ade503dfSGreg Roach $menu = new Menu(I18N::translate('Language'), '#', 'menu-language'); 326ade503dfSGreg Roach 327ade503dfSGreg Roach foreach (I18N::activeLocales() as $locale) { 328ade503dfSGreg Roach $language_tag = $locale->languageTag(); 329ade503dfSGreg Roach $class = 'menu-language-' . $language_tag . (WT_LOCALE === $language_tag ? ' active' : ''); 330ade503dfSGreg Roach $menu->addSubmenu(new Menu($locale->endonym(), '#', $class, [ 331ade503dfSGreg Roach 'onclick' => 'return false;', 332ade503dfSGreg Roach 'data-language' => $language_tag, 333ade503dfSGreg Roach ])); 334ade503dfSGreg Roach } 335ade503dfSGreg Roach 336ade503dfSGreg Roach if (count($menu->getSubmenus()) > 1) { 337ade503dfSGreg Roach return $menu; 338ade503dfSGreg Roach } 339ade503dfSGreg Roach 340ade503dfSGreg Roach return null; 341ade503dfSGreg Roach } 342ade503dfSGreg Roach 343ade503dfSGreg Roach /** 344ade503dfSGreg Roach * A login menu option (or null if we are already logged in). 345ade503dfSGreg Roach * 346ade503dfSGreg Roach * @return Menu|null 347ade503dfSGreg Roach */ 348ade503dfSGreg Roach public function menuLogin() 349ade503dfSGreg Roach { 350ade503dfSGreg Roach if (Auth::check()) { 351ade503dfSGreg Roach return null; 352ade503dfSGreg Roach } 353ade503dfSGreg Roach 354ade503dfSGreg Roach // Return to this page after login... 355ade503dfSGreg Roach $url = $this->request->getRequestUri(); 356ade503dfSGreg Roach 357ade503dfSGreg Roach // ...but switch from the tree-page to the user-page 358ade503dfSGreg Roach $url = str_replace('route=tree-page', 'route=user-page', $url); 359ade503dfSGreg Roach 360ade503dfSGreg Roach return new Menu(I18N::translate('Sign in'), route('login', ['url' => $url]), 'menu-login', ['rel' => 'nofollow']); 361ade503dfSGreg Roach } 362ade503dfSGreg Roach 363ade503dfSGreg Roach /** 364ade503dfSGreg Roach * A logout menu option (or null if we are already logged out). 365ade503dfSGreg Roach * 366ade503dfSGreg Roach * @return Menu|null 367ade503dfSGreg Roach */ 368ade503dfSGreg Roach public function menuLogout() 369ade503dfSGreg Roach { 370ade503dfSGreg Roach if (Auth::check()) { 371ade503dfSGreg Roach return new Menu(I18N::translate('Sign out'), route('logout'), 'menu-logout'); 372ade503dfSGreg Roach } 373ade503dfSGreg Roach 374ade503dfSGreg Roach return null; 375ade503dfSGreg Roach } 376ade503dfSGreg Roach 377ade503dfSGreg Roach /** 378ade503dfSGreg Roach * A link to allow users to edit their account settings. 379ade503dfSGreg Roach * 380ade503dfSGreg Roach * @return Menu|null 381ade503dfSGreg Roach */ 382ade503dfSGreg Roach public function menuMyAccount() 383ade503dfSGreg Roach { 384ade503dfSGreg Roach if (Auth::check()) { 385ade503dfSGreg Roach return new Menu(I18N::translate('My account'), route('my-account')); 386ade503dfSGreg Roach } 387ade503dfSGreg Roach 388ade503dfSGreg Roach return null; 389ade503dfSGreg Roach } 390ade503dfSGreg Roach 391ade503dfSGreg Roach /** 392ade503dfSGreg Roach * A link to the user's individual record (individual.php). 393ade503dfSGreg Roach * 394ade503dfSGreg Roach * @return Menu|null 395ade503dfSGreg Roach */ 396ade503dfSGreg Roach public function menuMyIndividualRecord() 397ade503dfSGreg Roach { 398ade503dfSGreg Roach $record = Individual::getInstance($this->tree->getUserPreference(Auth::user(), 'gedcomid'), $this->tree); 399ade503dfSGreg Roach 400ade503dfSGreg Roach if ($record) { 401ade503dfSGreg Roach return new Menu(I18N::translate('My individual record'), $record->url(), 'menu-myrecord'); 402ade503dfSGreg Roach } 403ade503dfSGreg Roach 404ade503dfSGreg Roach return null; 405ade503dfSGreg Roach } 406ade503dfSGreg Roach 407ade503dfSGreg Roach /** 408ade503dfSGreg Roach * A link to the user's personal home page. 409ade503dfSGreg Roach * 410ade503dfSGreg Roach * @return Menu 411ade503dfSGreg Roach */ 412ade503dfSGreg Roach public function menuMyPage(): Menu 413ade503dfSGreg Roach { 414ade503dfSGreg Roach return new Menu(I18N::translate('My page'), route('user-page', ['ged' => $this->tree->name()]), 'menu-mypage'); 415ade503dfSGreg Roach } 416ade503dfSGreg Roach 417ade503dfSGreg Roach /** 418ade503dfSGreg Roach * A menu for the user's personal pages. 419ade503dfSGreg Roach * 420ade503dfSGreg Roach * @return Menu|null 421ade503dfSGreg Roach */ 422ade503dfSGreg Roach public function menuMyPages() 423ade503dfSGreg Roach { 424ade503dfSGreg Roach if (Auth::id() && $this->tree !== null) { 425ade503dfSGreg Roach return new Menu(I18N::translate('My pages'), '#', 'menu-mymenu', [], array_filter([ 426ade503dfSGreg Roach $this->menuMyPage(), 427ade503dfSGreg Roach $this->menuMyIndividualRecord(), 428ade503dfSGreg Roach $this->menuMyPedigree(), 429ade503dfSGreg Roach $this->menuMyAccount(), 430ade503dfSGreg Roach $this->menuControlPanel(), 431ade503dfSGreg Roach $this->menuChangeBlocks(), 432ade503dfSGreg Roach ])); 433ade503dfSGreg Roach } 434ade503dfSGreg Roach 435ade503dfSGreg Roach return null; 436ade503dfSGreg Roach } 437ade503dfSGreg Roach 438ade503dfSGreg Roach /** 439ade503dfSGreg Roach * A link to the user's individual record. 440ade503dfSGreg Roach * 441ade503dfSGreg Roach * @return Menu|null 442ade503dfSGreg Roach */ 443ade503dfSGreg Roach public function menuMyPedigree() 444ade503dfSGreg Roach { 445ade503dfSGreg Roach $gedcomid = $this->tree->getUserPreference(Auth::user(), 'gedcomid'); 446ade503dfSGreg Roach 4474ca7e03cSGreg Roach $pedigree_chart = app(ModuleService::class)->findByComponent('chart', $this->tree, Auth::user()) 448ade503dfSGreg Roach ->filter(function (ModuleInterface $module): bool { 449ade503dfSGreg Roach return $module instanceof PedigreeChartModule; 450ade503dfSGreg Roach }); 451ade503dfSGreg Roach 452ade503dfSGreg Roach if ($gedcomid !== '' && $pedigree_chart instanceof PedigreeChartModule) { 453ade503dfSGreg Roach return new Menu( 454ade503dfSGreg Roach I18N::translate('My pedigree'), 455ade503dfSGreg Roach route('pedigree', [ 456ade503dfSGreg Roach 'xref' => $gedcomid, 457ade503dfSGreg Roach 'ged' => $this->tree->name(), 458ade503dfSGreg Roach ]), 459ade503dfSGreg Roach 'menu-mypedigree' 460ade503dfSGreg Roach ); 461ade503dfSGreg Roach } 462ade503dfSGreg Roach 463ade503dfSGreg Roach return null; 464ade503dfSGreg Roach } 465ade503dfSGreg Roach 466ade503dfSGreg Roach /** 467ade503dfSGreg Roach * Create a pending changes menu. 468ade503dfSGreg Roach * 469ade503dfSGreg Roach * @return Menu|null 470ade503dfSGreg Roach */ 471ade503dfSGreg Roach public function menuPendingChanges() 472ade503dfSGreg Roach { 473ade503dfSGreg Roach if ($this->pendingChangesExist()) { 474ade503dfSGreg Roach $url = route('show-pending', [ 475ade503dfSGreg Roach 'ged' => $this->tree ? $this->tree->name() : '', 476ade503dfSGreg Roach 'url' => $this->request->getRequestUri(), 477ade503dfSGreg Roach ]); 478ade503dfSGreg Roach 479ade503dfSGreg Roach return new Menu(I18N::translate('Pending changes'), $url, 'menu-pending'); 480ade503dfSGreg Roach } 481ade503dfSGreg Roach 482ade503dfSGreg Roach return null; 483ade503dfSGreg Roach } 484ade503dfSGreg Roach 485ade503dfSGreg Roach /** 486ade503dfSGreg Roach * Themes menu. 487ade503dfSGreg Roach * 488ade503dfSGreg Roach * @return Menu|null 489ade503dfSGreg Roach */ 490ade503dfSGreg Roach public function menuThemes() 491ade503dfSGreg Roach { 4924ca7e03cSGreg Roach $themes = app(ModuleService::class)->findByInterface(ModuleThemeInterface::class); 493df8baf00SGreg Roach 4948136679eSGreg Roach $current_theme = app()->make(ModuleThemeInterface::class); 4958136679eSGreg Roach 4968136679eSGreg Roach if ($themes->count() > 1) { 4978136679eSGreg Roach $submenus = $themes->map(function (ModuleThemeInterface $theme) use ($current_theme): Menu { 4988136679eSGreg Roach $active = $theme->name() === $current_theme->name(); 4998136679eSGreg Roach $class = 'menu-theme-' . $theme->name() . ($active ? ' active' : ''); 5008136679eSGreg Roach 5018136679eSGreg Roach return new Menu($theme->title(), '#', $class, [ 502ade503dfSGreg Roach 'onclick' => 'return false;', 503ade503dfSGreg Roach 'data-theme' => $theme->name(), 504ade503dfSGreg Roach ]); 505ade503dfSGreg Roach }); 506ade503dfSGreg Roach 5078136679eSGreg Roach return new Menu(I18N::translate('Theme'), '#', 'menu-theme', [], $submenus->all()); 508ade503dfSGreg Roach } 509ade503dfSGreg Roach 510ade503dfSGreg Roach return null; 511ade503dfSGreg Roach } 512ade503dfSGreg Roach 513ade503dfSGreg Roach /** 514ade503dfSGreg Roach * Misecellaneous dimensions, fonts, styles, etc. 515ade503dfSGreg Roach * 516ade503dfSGreg Roach * @param string $parameter_name 517ade503dfSGreg Roach * 518ade503dfSGreg Roach * @return string|int|float 519ade503dfSGreg Roach */ 520ade503dfSGreg Roach public function parameter($parameter_name) 521ade503dfSGreg Roach { 522ade503dfSGreg Roach return ''; 523ade503dfSGreg Roach } 524ade503dfSGreg Roach 525ade503dfSGreg Roach /** 526ade503dfSGreg Roach * Are there any pending changes for us to approve? 527ade503dfSGreg Roach * 528ade503dfSGreg Roach * @return bool 529ade503dfSGreg Roach */ 530ade503dfSGreg Roach public function pendingChangesExist(): bool 531ade503dfSGreg Roach { 532ade503dfSGreg Roach return $this->tree && $this->tree->hasPendingEdit() && Auth::isModerator($this->tree); 533ade503dfSGreg Roach } 534ade503dfSGreg Roach 535ade503dfSGreg Roach /** 536ade503dfSGreg Roach * Generate a list of items for the main menu. 537ade503dfSGreg Roach * 538ade503dfSGreg Roach * @return Menu[] 539ade503dfSGreg Roach */ 540ade503dfSGreg Roach public function primaryMenu(): array 541ade503dfSGreg Roach { 5424ca7e03cSGreg Roach return app(ModuleService::class)->findByComponent('menu', $this->tree, Auth::user()) 543ade503dfSGreg Roach ->map(function (ModuleMenuInterface $menu): ?Menu { 544ade503dfSGreg Roach return $menu->getMenu($this->tree); 545ade503dfSGreg Roach }) 546ade503dfSGreg Roach ->filter() 547ade503dfSGreg Roach ->all(); 548ade503dfSGreg Roach } 549ade503dfSGreg Roach 550ade503dfSGreg Roach /** 551ade503dfSGreg Roach * Create the primary menu. 552ade503dfSGreg Roach * 553ade503dfSGreg Roach * @param Menu[] $menus 554ade503dfSGreg Roach * 555ade503dfSGreg Roach * @return string 556ade503dfSGreg Roach */ 557ade503dfSGreg Roach public function primaryMenuContent(array $menus): string 558ade503dfSGreg Roach { 559ade503dfSGreg Roach return implode('', array_map(function (Menu $menu): string { 560ade503dfSGreg Roach return $menu->bootstrap4(); 561ade503dfSGreg Roach }, $menus)); 562ade503dfSGreg Roach } 563ade503dfSGreg Roach 564ade503dfSGreg Roach /** 565ade503dfSGreg Roach * Generate a list of items for the user menu. 566ade503dfSGreg Roach * 567ade503dfSGreg Roach * @return Menu[] 568ade503dfSGreg Roach */ 569ade503dfSGreg Roach public function secondaryMenu(): array 570ade503dfSGreg Roach { 571ade503dfSGreg Roach return array_filter([ 572ade503dfSGreg Roach $this->menuPendingChanges(), 573ade503dfSGreg Roach $this->menuMyPages(), 574ade503dfSGreg Roach $this->menuThemes(), 575ade503dfSGreg Roach $this->menuLanguages(), 576ade503dfSGreg Roach $this->menuLogin(), 577ade503dfSGreg Roach $this->menuLogout(), 578ade503dfSGreg Roach ]); 579ade503dfSGreg Roach } 580ade503dfSGreg Roach 581ade503dfSGreg Roach /** 582ade503dfSGreg Roach * A list of CSS files to include for this page. 583ade503dfSGreg Roach * 584ade503dfSGreg Roach * @return string[] 585ade503dfSGreg Roach */ 586ade503dfSGreg Roach public function stylesheets(): array 587ade503dfSGreg Roach { 588ade503dfSGreg Roach return []; 589ade503dfSGreg Roach } 59049a243cbSGreg Roach} 591