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 * 82*e837ff07SGreg Roach * @TODO use CSS for this 83*e837ff07SGreg Roach * 84ade503dfSGreg Roach * @param Fact $fact 85ade503dfSGreg Roach * 86ade503dfSGreg Roach * @return string 87ade503dfSGreg Roach */ 88ade503dfSGreg Roach public function icon(Fact $fact): string 89ade503dfSGreg Roach { 90*e837ff07SGreg Roach $asset = 'public/css/' . $this->name() . '/images/facts/' . $fact->getTag() . '.png'; 91*e837ff07SGreg Roach if (file_exists(WT_ROOT . 'public' . $asset)) { 92*e837ff07SGreg 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. 96*e837ff07SGreg Roach $asset = 'public/css/' . $this->name() . '/images/facts/NULL.png'; 97*e837ff07SGreg Roach if (file_exists(WT_ROOT . 'public' . $asset)) { 98*e837ff07SGreg 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 { 113ade503dfSGreg Roach $person_box_class = self::PERSON_BOX_CLASSES[$individual->getSex()]; 114ade503dfSGreg Roach 115ade503dfSGreg Roach if ($individual->canShow() && $individual->tree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) { 116ade503dfSGreg Roach $thumbnail = $individual->displayImage(40, 50, 'crop', []); 117ade503dfSGreg Roach } else { 118ade503dfSGreg Roach $thumbnail = ''; 119ade503dfSGreg Roach } 120ade503dfSGreg Roach 121ade503dfSGreg Roach $content = '<span class="namedef name1">' . $individual->getFullName() . '</span>'; 122ade503dfSGreg Roach $icons = ''; 123ade503dfSGreg Roach if ($individual->canShow()) { 124ade503dfSGreg Roach $content = '<a href="' . e($individual->url()) . '">' . $content . '</a>' . 125ade503dfSGreg Roach '<div class="namedef name1">' . $individual->getAddName() . '</div>'; 126ade503dfSGreg Roach $icons = '<div class="icons">' . 127ade503dfSGreg Roach '<span class="iconz icon-zoomin" title="' . I18N::translate('Zoom in/out on this box.') . '"></span>' . 128ade503dfSGreg Roach '<div class="itr"><i class="icon-pedigree"></i><div class="popup">' . 129ade503dfSGreg Roach '<ul class="' . $person_box_class . '">' . implode('', array_map(function (Menu $menu): string { 130ade503dfSGreg Roach return $menu->bootstrap4(); 131ade503dfSGreg Roach }, $this->individualBoxMenu($individual))) . '</ul>' . 132ade503dfSGreg Roach '</div>' . 133ade503dfSGreg Roach '</div>' . 134ade503dfSGreg Roach '</div>'; 135ade503dfSGreg Roach } 136ade503dfSGreg Roach 137ade503dfSGreg Roach return 138ade503dfSGreg Roach '<div data-xref="' . e($individual->xref()) . '" data-tree="' . e($individual->tree()->name()) . '" class="person_box_template ' . $person_box_class . ' box-style1" style="width: ' . $this->parameter('chart-box-x') . 'px; height: ' . $this->parameter('chart-box-y') . 'px">' . 139ade503dfSGreg Roach $icons . 140ade503dfSGreg Roach '<div class="chart_textbox" style="max-height:' . $this->parameter('chart-box-y') . 'px;">' . 141ade503dfSGreg Roach $thumbnail . 142ade503dfSGreg Roach $content . 143ade503dfSGreg Roach '<div class="inout2 details1">' . $this->individualBoxFacts($individual) . '</div>' . 144ade503dfSGreg Roach '</div>' . 145ade503dfSGreg Roach '<div class="inout"></div>' . 146ade503dfSGreg Roach '</div>'; 147ade503dfSGreg Roach } 148ade503dfSGreg Roach 149ade503dfSGreg Roach /** 150ade503dfSGreg Roach * Display an empty box - for a missing individual in a chart. 151ade503dfSGreg Roach * 152ade503dfSGreg Roach * @return string 153ade503dfSGreg Roach */ 154ade503dfSGreg Roach public function individualBoxEmpty(): string 155ade503dfSGreg Roach { 156ade503dfSGreg Roach return '<div class="person_box_template person_boxNN box-style1" style="width: ' . $this->parameter('chart-box-x') . 'px; min-height: ' . $this->parameter('chart-box-y') . 'px"></div>'; 157ade503dfSGreg Roach } 158ade503dfSGreg Roach 159ade503dfSGreg Roach /** 160ade503dfSGreg Roach * Display an individual in a box - for charts, etc. 161ade503dfSGreg Roach * 162ade503dfSGreg Roach * @param Individual $individual 163ade503dfSGreg Roach * 164ade503dfSGreg Roach * @return string 165ade503dfSGreg Roach */ 166ade503dfSGreg Roach public function individualBoxLarge(Individual $individual): string 167ade503dfSGreg Roach { 168ade503dfSGreg Roach $person_box_class = self::PERSON_BOX_CLASSES[$individual->getSex()]; 169ade503dfSGreg Roach 170ade503dfSGreg Roach if ($individual->tree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) { 171ade503dfSGreg Roach $thumbnail = $individual->displayImage(40, 50, 'crop', []); 172ade503dfSGreg Roach } else { 173ade503dfSGreg Roach $thumbnail = ''; 174ade503dfSGreg Roach } 175ade503dfSGreg Roach 176ade503dfSGreg Roach $content = '<span class="namedef name1">' . $individual->getFullName() . '</span>'; 177ade503dfSGreg Roach $icons = ''; 178ade503dfSGreg Roach if ($individual->canShow()) { 179ade503dfSGreg Roach $content = '<a href="' . e($individual->url()) . '">' . $content . '</a>' . 180ade503dfSGreg Roach '<div class="namedef name2">' . $individual->getAddName() . '</div>'; 181ade503dfSGreg Roach $icons = '<div class="icons">' . 182ade503dfSGreg Roach '<span class="iconz icon-zoomin" title="' . I18N::translate('Zoom in/out on this box.') . '"></span>' . 183ade503dfSGreg Roach '<div class="itr"><i class="icon-pedigree"></i><div class="popup">' . 184ade503dfSGreg Roach '<ul class="' . $person_box_class . '">' . implode('', array_map(function (Menu $menu): string { 185ade503dfSGreg Roach return $menu->bootstrap4(); 186ade503dfSGreg Roach }, $this->individualBoxMenu($individual))) . '</ul>' . 187ade503dfSGreg Roach '</div>' . 188ade503dfSGreg Roach '</div>' . 189ade503dfSGreg Roach '</div>'; 190ade503dfSGreg Roach } 191ade503dfSGreg Roach 192ade503dfSGreg Roach return 193ade503dfSGreg Roach '<div data-xref="' . e($individual->xref()) . '" data-tree="' . e($individual->tree()->name()) . '" class="person_box_template ' . $person_box_class . ' box-style2">' . 194ade503dfSGreg Roach $icons . 195ade503dfSGreg Roach '<div class="chart_textbox" style="max-height:' . $this->parameter('chart-box-y') . 'px;">' . 196ade503dfSGreg Roach $thumbnail . 197ade503dfSGreg Roach $content . 198ade503dfSGreg Roach '<div class="inout2 details2">' . $this->individualBoxFacts($individual) . '</div>' . 199ade503dfSGreg Roach '</div>' . 200ade503dfSGreg Roach '<div class="inout"></div>' . 201ade503dfSGreg Roach '</div>'; 202ade503dfSGreg Roach } 203ade503dfSGreg Roach 204ade503dfSGreg Roach /** 205ade503dfSGreg Roach * Display an individual in a box - for charts, etc. 206ade503dfSGreg Roach * 207ade503dfSGreg Roach * @param Individual $individual 208ade503dfSGreg Roach * 209ade503dfSGreg Roach * @return string 210ade503dfSGreg Roach */ 211ade503dfSGreg Roach public function individualBoxSmall(Individual $individual): string 212ade503dfSGreg Roach { 213ade503dfSGreg Roach $person_box_class = self::PERSON_BOX_CLASSES[$individual->getSex()]; 214ade503dfSGreg Roach 215ade503dfSGreg Roach if ($individual->tree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) { 216ade503dfSGreg Roach $thumbnail = $individual->displayImage(40, 50, 'crop', []); 217ade503dfSGreg Roach } else { 218ade503dfSGreg Roach $thumbnail = ''; 219ade503dfSGreg Roach } 220ade503dfSGreg Roach 221ade503dfSGreg Roach return 222ade503dfSGreg Roach '<div data-xref="' . $individual->xref() . '" class="person_box_template ' . $person_box_class . ' iconz box-style0" style="width: ' . $this->parameter('compact-chart-box-x') . 'px; min-height: ' . $this->parameter('compact-chart-box-y') . 'px">' . 223ade503dfSGreg Roach '<div class="compact_view">' . 224ade503dfSGreg Roach $thumbnail . 225ade503dfSGreg Roach '<a href="' . e($individual->url()) . '">' . 226ade503dfSGreg Roach '<span class="namedef name0">' . $individual->getFullName() . '</span>' . 227ade503dfSGreg Roach '</a>' . 228ade503dfSGreg Roach '<div class="inout2 details0">' . $individual->getLifeSpan() . '</div>' . 229ade503dfSGreg Roach '</div>' . 230ade503dfSGreg Roach '<div class="inout"></div>' . 231ade503dfSGreg Roach '</div>'; 232ade503dfSGreg Roach } 233ade503dfSGreg Roach 234ade503dfSGreg Roach /** 235ade503dfSGreg Roach * Display an individual in a box - for charts, etc. 236ade503dfSGreg Roach * 237ade503dfSGreg Roach * @return string 238ade503dfSGreg Roach */ 239ade503dfSGreg Roach public function individualBoxSmallEmpty(): string 240ade503dfSGreg Roach { 241ade503dfSGreg Roach return '<div class="person_box_template person_boxNN box-style1" style="width: ' . $this->parameter('compact-chart-box-x') . 'px; min-height: ' . $this->parameter('compact-chart-box-y') . 'px"></div>'; 242ade503dfSGreg Roach } 243ade503dfSGreg Roach 244ade503dfSGreg Roach /** 245ade503dfSGreg Roach * Generate the facts, for display in charts. 246ade503dfSGreg Roach * 247ade503dfSGreg Roach * @param Individual $individual 248ade503dfSGreg Roach * 249ade503dfSGreg Roach * @return string 250ade503dfSGreg Roach */ 251ade503dfSGreg Roach public function individualBoxFacts(Individual $individual): string 252ade503dfSGreg Roach { 253ade503dfSGreg Roach $html = ''; 254ade503dfSGreg Roach 255ade503dfSGreg Roach $opt_tags = preg_split('/\W/', $individual->tree()->getPreference('CHART_BOX_TAGS'), 0, PREG_SPLIT_NO_EMPTY); 256ade503dfSGreg Roach // Show BIRT or equivalent event 257ade503dfSGreg Roach foreach (Gedcom::BIRTH_EVENTS as $birttag) { 258ade503dfSGreg Roach if (!in_array($birttag, $opt_tags)) { 259ade503dfSGreg Roach $event = $individual->getFirstFact($birttag); 260ade503dfSGreg Roach if ($event) { 261ade503dfSGreg Roach $html .= $event->summary(); 262ade503dfSGreg Roach break; 263ade503dfSGreg Roach } 264ade503dfSGreg Roach } 265ade503dfSGreg Roach } 266ade503dfSGreg Roach // Show optional events (before death) 267ade503dfSGreg Roach foreach ($opt_tags as $key => $tag) { 268ade503dfSGreg Roach if (!in_array($tag, Gedcom::DEATH_EVENTS)) { 269ade503dfSGreg Roach $event = $individual->getFirstFact($tag); 270ade503dfSGreg Roach if ($event !== null) { 271ade503dfSGreg Roach $html .= $event->summary(); 272ade503dfSGreg Roach unset($opt_tags[$key]); 273ade503dfSGreg Roach } 274ade503dfSGreg Roach } 275ade503dfSGreg Roach } 276ade503dfSGreg Roach // Show DEAT or equivalent event 277ade503dfSGreg Roach foreach (Gedcom::DEATH_EVENTS as $deattag) { 278ade503dfSGreg Roach $event = $individual->getFirstFact($deattag); 279ade503dfSGreg Roach if ($event) { 280ade503dfSGreg Roach $html .= $event->summary(); 281ade503dfSGreg Roach if (in_array($deattag, $opt_tags)) { 282ade503dfSGreg Roach unset($opt_tags[array_search($deattag, $opt_tags)]); 283ade503dfSGreg Roach } 284ade503dfSGreg Roach break; 285ade503dfSGreg Roach } 286ade503dfSGreg Roach } 287ade503dfSGreg Roach // Show remaining optional events (after death) 288ade503dfSGreg Roach foreach ($opt_tags as $tag) { 289ade503dfSGreg Roach $event = $individual->getFirstFact($tag); 290ade503dfSGreg Roach if ($event) { 291ade503dfSGreg Roach $html .= $event->summary(); 292ade503dfSGreg Roach } 293ade503dfSGreg Roach } 294ade503dfSGreg Roach 295ade503dfSGreg Roach return $html; 296ade503dfSGreg Roach } 297ade503dfSGreg Roach 298ade503dfSGreg Roach /** 299ade503dfSGreg Roach * Links, to show in chart boxes; 300ade503dfSGreg Roach * 301ade503dfSGreg Roach * @param Individual $individual 302ade503dfSGreg Roach * 303ade503dfSGreg Roach * @return Menu[] 304ade503dfSGreg Roach */ 305ade503dfSGreg Roach public function individualBoxMenu(Individual $individual): array 306ade503dfSGreg Roach { 307ade503dfSGreg Roach $menus = array_merge( 308ade503dfSGreg Roach $this->individualBoxMenuCharts($individual), 309ade503dfSGreg Roach $this->individualBoxMenuFamilyLinks($individual) 310ade503dfSGreg Roach ); 311ade503dfSGreg Roach 312ade503dfSGreg Roach return $menus; 313ade503dfSGreg Roach } 314ade503dfSGreg Roach 315ade503dfSGreg Roach /** 316ade503dfSGreg Roach * Chart links, to show in chart boxes; 317ade503dfSGreg Roach * 318ade503dfSGreg Roach * @param Individual $individual 319ade503dfSGreg Roach * 320ade503dfSGreg Roach * @return Menu[] 321ade503dfSGreg Roach */ 322ade503dfSGreg Roach public function individualBoxMenuCharts(Individual $individual): array 323ade503dfSGreg Roach { 324ade503dfSGreg Roach $menus = []; 3254ca7e03cSGreg Roach foreach (app(ModuleService::class)->findByComponent('chart', $this->tree, Auth::user()) as $chart) { 326ade503dfSGreg Roach $menu = $chart->chartBoxMenu($individual); 327ade503dfSGreg Roach if ($menu) { 328ade503dfSGreg Roach $menus[] = $menu; 329ade503dfSGreg Roach } 330ade503dfSGreg Roach } 331ade503dfSGreg Roach 332ade503dfSGreg Roach usort($menus, function (Menu $x, Menu $y) { 333ade503dfSGreg Roach return I18N::strcasecmp($x->getLabel(), $y->getLabel()); 334ade503dfSGreg Roach }); 335ade503dfSGreg Roach 336ade503dfSGreg Roach return $menus; 337ade503dfSGreg Roach } 338ade503dfSGreg Roach 339ade503dfSGreg Roach /** 340ade503dfSGreg Roach * Family links, to show in chart boxes. 341ade503dfSGreg Roach * 342ade503dfSGreg Roach * @param Individual $individual 343ade503dfSGreg Roach * 344ade503dfSGreg Roach * @return Menu[] 345ade503dfSGreg Roach */ 346ade503dfSGreg Roach public function individualBoxMenuFamilyLinks(Individual $individual): array 347ade503dfSGreg Roach { 348ade503dfSGreg Roach $menus = []; 349ade503dfSGreg Roach 350ade503dfSGreg Roach foreach ($individual->getSpouseFamilies() as $family) { 351ade503dfSGreg Roach $menus[] = new Menu('<strong>' . I18N::translate('Family with spouse') . '</strong>', $family->url()); 352ade503dfSGreg Roach $spouse = $family->getSpouse($individual); 353ade503dfSGreg Roach if ($spouse && $spouse->canShowName()) { 354ade503dfSGreg Roach $menus[] = new Menu($spouse->getFullName(), $spouse->url()); 355ade503dfSGreg Roach } 356ade503dfSGreg Roach foreach ($family->getChildren() as $child) { 357ade503dfSGreg Roach if ($child->canShowName()) { 358ade503dfSGreg Roach $menus[] = new Menu($child->getFullName(), $child->url()); 359ade503dfSGreg Roach } 360ade503dfSGreg Roach } 361ade503dfSGreg Roach } 362ade503dfSGreg Roach 363ade503dfSGreg Roach return $menus; 364ade503dfSGreg Roach } 365ade503dfSGreg Roach 366ade503dfSGreg Roach /** 367ade503dfSGreg Roach * Generate a menu item to change the blocks on the current (index.php) page. 368ade503dfSGreg Roach * 369ade503dfSGreg Roach * @return Menu|null 370ade503dfSGreg Roach */ 371ade503dfSGreg Roach public function menuChangeBlocks() 372ade503dfSGreg Roach { 373ade503dfSGreg Roach if (Auth::check() && $this->request->get('route') === 'user-page') { 374ade503dfSGreg Roach return new Menu(I18N::translate('Customize this page'), route('user-page-edit', ['ged' => $this->tree->name()]), 'menu-change-blocks'); 375ade503dfSGreg Roach } 376ade503dfSGreg Roach 377ade503dfSGreg Roach if (Auth::isManager($this->tree) && $this->request->get('route') === 'tree-page') { 378ade503dfSGreg Roach return new Menu(I18N::translate('Customize this page'), route('tree-page-edit', ['ged' => $this->tree->name()]), 'menu-change-blocks'); 379ade503dfSGreg Roach } 380ade503dfSGreg Roach 381ade503dfSGreg Roach return null; 382ade503dfSGreg Roach } 383ade503dfSGreg Roach 384ade503dfSGreg Roach /** 385ade503dfSGreg Roach * Generate a menu item for the control panel. 386ade503dfSGreg Roach * 387ade503dfSGreg Roach * @return Menu|null 388ade503dfSGreg Roach */ 389ade503dfSGreg Roach public function menuControlPanel() 390ade503dfSGreg Roach { 391ade503dfSGreg Roach if (Auth::isAdmin()) { 392ade503dfSGreg Roach return new Menu(I18N::translate('Control panel'), route('admin-control-panel'), 'menu-admin'); 393ade503dfSGreg Roach } 394ade503dfSGreg Roach 395ade503dfSGreg Roach if (Auth::isManager($this->tree)) { 396ade503dfSGreg Roach return new Menu(I18N::translate('Control panel'), route('admin-control-panel-manager'), 'menu-admin'); 397ade503dfSGreg Roach } 398ade503dfSGreg Roach 399ade503dfSGreg Roach return null; 400ade503dfSGreg Roach } 401ade503dfSGreg Roach 402ade503dfSGreg Roach /** 403ade503dfSGreg Roach * A menu to show a list of available languages. 404ade503dfSGreg Roach * 405ade503dfSGreg Roach * @return Menu|null 406ade503dfSGreg Roach */ 407ade503dfSGreg Roach public function menuLanguages() 408ade503dfSGreg Roach { 409ade503dfSGreg Roach $menu = new Menu(I18N::translate('Language'), '#', 'menu-language'); 410ade503dfSGreg Roach 411ade503dfSGreg Roach foreach (I18N::activeLocales() as $locale) { 412ade503dfSGreg Roach $language_tag = $locale->languageTag(); 413ade503dfSGreg Roach $class = 'menu-language-' . $language_tag . (WT_LOCALE === $language_tag ? ' active' : ''); 414ade503dfSGreg Roach $menu->addSubmenu(new Menu($locale->endonym(), '#', $class, [ 415ade503dfSGreg Roach 'onclick' => 'return false;', 416ade503dfSGreg Roach 'data-language' => $language_tag, 417ade503dfSGreg Roach ])); 418ade503dfSGreg Roach } 419ade503dfSGreg Roach 420ade503dfSGreg Roach if (count($menu->getSubmenus()) > 1) { 421ade503dfSGreg Roach return $menu; 422ade503dfSGreg Roach } 423ade503dfSGreg Roach 424ade503dfSGreg Roach return null; 425ade503dfSGreg Roach } 426ade503dfSGreg Roach 427ade503dfSGreg Roach /** 428ade503dfSGreg Roach * A login menu option (or null if we are already logged in). 429ade503dfSGreg Roach * 430ade503dfSGreg Roach * @return Menu|null 431ade503dfSGreg Roach */ 432ade503dfSGreg Roach public function menuLogin() 433ade503dfSGreg Roach { 434ade503dfSGreg Roach if (Auth::check()) { 435ade503dfSGreg Roach return null; 436ade503dfSGreg Roach } 437ade503dfSGreg Roach 438ade503dfSGreg Roach // Return to this page after login... 439ade503dfSGreg Roach $url = $this->request->getRequestUri(); 440ade503dfSGreg Roach 441ade503dfSGreg Roach // ...but switch from the tree-page to the user-page 442ade503dfSGreg Roach $url = str_replace('route=tree-page', 'route=user-page', $url); 443ade503dfSGreg Roach 444ade503dfSGreg Roach return new Menu(I18N::translate('Sign in'), route('login', ['url' => $url]), 'menu-login', ['rel' => 'nofollow']); 445ade503dfSGreg Roach } 446ade503dfSGreg Roach 447ade503dfSGreg Roach /** 448ade503dfSGreg Roach * A logout menu option (or null if we are already logged out). 449ade503dfSGreg Roach * 450ade503dfSGreg Roach * @return Menu|null 451ade503dfSGreg Roach */ 452ade503dfSGreg Roach public function menuLogout() 453ade503dfSGreg Roach { 454ade503dfSGreg Roach if (Auth::check()) { 455ade503dfSGreg Roach return new Menu(I18N::translate('Sign out'), route('logout'), 'menu-logout'); 456ade503dfSGreg Roach } 457ade503dfSGreg Roach 458ade503dfSGreg Roach return null; 459ade503dfSGreg Roach } 460ade503dfSGreg Roach 461ade503dfSGreg Roach /** 462ade503dfSGreg Roach * A link to allow users to edit their account settings. 463ade503dfSGreg Roach * 464ade503dfSGreg Roach * @return Menu|null 465ade503dfSGreg Roach */ 466ade503dfSGreg Roach public function menuMyAccount() 467ade503dfSGreg Roach { 468ade503dfSGreg Roach if (Auth::check()) { 469ade503dfSGreg Roach return new Menu(I18N::translate('My account'), route('my-account')); 470ade503dfSGreg Roach } 471ade503dfSGreg Roach 472ade503dfSGreg Roach return null; 473ade503dfSGreg Roach } 474ade503dfSGreg Roach 475ade503dfSGreg Roach /** 476ade503dfSGreg Roach * A link to the user's individual record (individual.php). 477ade503dfSGreg Roach * 478ade503dfSGreg Roach * @return Menu|null 479ade503dfSGreg Roach */ 480ade503dfSGreg Roach public function menuMyIndividualRecord() 481ade503dfSGreg Roach { 482ade503dfSGreg Roach $record = Individual::getInstance($this->tree->getUserPreference(Auth::user(), 'gedcomid'), $this->tree); 483ade503dfSGreg Roach 484ade503dfSGreg Roach if ($record) { 485ade503dfSGreg Roach return new Menu(I18N::translate('My individual record'), $record->url(), 'menu-myrecord'); 486ade503dfSGreg Roach } 487ade503dfSGreg Roach 488ade503dfSGreg Roach return null; 489ade503dfSGreg Roach } 490ade503dfSGreg Roach 491ade503dfSGreg Roach /** 492ade503dfSGreg Roach * A link to the user's personal home page. 493ade503dfSGreg Roach * 494ade503dfSGreg Roach * @return Menu 495ade503dfSGreg Roach */ 496ade503dfSGreg Roach public function menuMyPage(): Menu 497ade503dfSGreg Roach { 498ade503dfSGreg Roach return new Menu(I18N::translate('My page'), route('user-page', ['ged' => $this->tree->name()]), 'menu-mypage'); 499ade503dfSGreg Roach } 500ade503dfSGreg Roach 501ade503dfSGreg Roach /** 502ade503dfSGreg Roach * A menu for the user's personal pages. 503ade503dfSGreg Roach * 504ade503dfSGreg Roach * @return Menu|null 505ade503dfSGreg Roach */ 506ade503dfSGreg Roach public function menuMyPages() 507ade503dfSGreg Roach { 508ade503dfSGreg Roach if (Auth::id() && $this->tree !== null) { 509ade503dfSGreg Roach return new Menu(I18N::translate('My pages'), '#', 'menu-mymenu', [], array_filter([ 510ade503dfSGreg Roach $this->menuMyPage(), 511ade503dfSGreg Roach $this->menuMyIndividualRecord(), 512ade503dfSGreg Roach $this->menuMyPedigree(), 513ade503dfSGreg Roach $this->menuMyAccount(), 514ade503dfSGreg Roach $this->menuControlPanel(), 515ade503dfSGreg Roach $this->menuChangeBlocks(), 516ade503dfSGreg Roach ])); 517ade503dfSGreg Roach } 518ade503dfSGreg Roach 519ade503dfSGreg Roach return null; 520ade503dfSGreg Roach } 521ade503dfSGreg Roach 522ade503dfSGreg Roach /** 523ade503dfSGreg Roach * A link to the user's individual record. 524ade503dfSGreg Roach * 525ade503dfSGreg Roach * @return Menu|null 526ade503dfSGreg Roach */ 527ade503dfSGreg Roach public function menuMyPedigree() 528ade503dfSGreg Roach { 529ade503dfSGreg Roach $gedcomid = $this->tree->getUserPreference(Auth::user(), 'gedcomid'); 530ade503dfSGreg Roach 5314ca7e03cSGreg Roach $pedigree_chart = app(ModuleService::class)->findByComponent('chart', $this->tree, Auth::user()) 532ade503dfSGreg Roach ->filter(function (ModuleInterface $module): bool { 533ade503dfSGreg Roach return $module instanceof PedigreeChartModule; 534ade503dfSGreg Roach }); 535ade503dfSGreg Roach 536ade503dfSGreg Roach if ($gedcomid !== '' && $pedigree_chart instanceof PedigreeChartModule) { 537ade503dfSGreg Roach return new Menu( 538ade503dfSGreg Roach I18N::translate('My pedigree'), 539ade503dfSGreg Roach route('pedigree', [ 540ade503dfSGreg Roach 'xref' => $gedcomid, 541ade503dfSGreg Roach 'ged' => $this->tree->name(), 542ade503dfSGreg Roach ]), 543ade503dfSGreg Roach 'menu-mypedigree' 544ade503dfSGreg Roach ); 545ade503dfSGreg Roach } 546ade503dfSGreg Roach 547ade503dfSGreg Roach return null; 548ade503dfSGreg Roach } 549ade503dfSGreg Roach 550ade503dfSGreg Roach /** 551ade503dfSGreg Roach * Create a pending changes menu. 552ade503dfSGreg Roach * 553ade503dfSGreg Roach * @return Menu|null 554ade503dfSGreg Roach */ 555ade503dfSGreg Roach public function menuPendingChanges() 556ade503dfSGreg Roach { 557ade503dfSGreg Roach if ($this->pendingChangesExist()) { 558ade503dfSGreg Roach $url = route('show-pending', [ 559ade503dfSGreg Roach 'ged' => $this->tree ? $this->tree->name() : '', 560ade503dfSGreg Roach 'url' => $this->request->getRequestUri(), 561ade503dfSGreg Roach ]); 562ade503dfSGreg Roach 563ade503dfSGreg Roach return new Menu(I18N::translate('Pending changes'), $url, 'menu-pending'); 564ade503dfSGreg Roach } 565ade503dfSGreg Roach 566ade503dfSGreg Roach return null; 567ade503dfSGreg Roach } 568ade503dfSGreg Roach 569ade503dfSGreg Roach /** 570ade503dfSGreg Roach * Themes menu. 571ade503dfSGreg Roach * 572ade503dfSGreg Roach * @return Menu|null 573ade503dfSGreg Roach */ 574ade503dfSGreg Roach public function menuThemes() 575ade503dfSGreg Roach { 5764ca7e03cSGreg Roach $themes = app(ModuleService::class)->findByInterface(ModuleThemeInterface::class); 577df8baf00SGreg Roach 5788136679eSGreg Roach $current_theme = app()->make(ModuleThemeInterface::class); 5798136679eSGreg Roach 5808136679eSGreg Roach if ($themes->count() > 1) { 5818136679eSGreg Roach $submenus = $themes->map(function (ModuleThemeInterface $theme) use ($current_theme): Menu { 5828136679eSGreg Roach $active = $theme->name() === $current_theme->name(); 5838136679eSGreg Roach $class = 'menu-theme-' . $theme->name() . ($active ? ' active' : ''); 5848136679eSGreg Roach 5858136679eSGreg Roach return new Menu($theme->title(), '#', $class, [ 586ade503dfSGreg Roach 'onclick' => 'return false;', 587ade503dfSGreg Roach 'data-theme' => $theme->name(), 588ade503dfSGreg Roach ]); 589ade503dfSGreg Roach }); 590ade503dfSGreg Roach 5918136679eSGreg Roach return new Menu(I18N::translate('Theme'), '#', 'menu-theme', [], $submenus->all()); 592ade503dfSGreg Roach } 593ade503dfSGreg Roach 594ade503dfSGreg Roach return null; 595ade503dfSGreg Roach } 596ade503dfSGreg Roach 597ade503dfSGreg Roach /** 598ade503dfSGreg Roach * Misecellaneous dimensions, fonts, styles, etc. 599ade503dfSGreg Roach * 600ade503dfSGreg Roach * @param string $parameter_name 601ade503dfSGreg Roach * 602ade503dfSGreg Roach * @return string|int|float 603ade503dfSGreg Roach */ 604ade503dfSGreg Roach public function parameter($parameter_name) 605ade503dfSGreg Roach { 606ade503dfSGreg Roach return ''; 607ade503dfSGreg Roach } 608ade503dfSGreg Roach 609ade503dfSGreg Roach /** 610ade503dfSGreg Roach * Are there any pending changes for us to approve? 611ade503dfSGreg Roach * 612ade503dfSGreg Roach * @return bool 613ade503dfSGreg Roach */ 614ade503dfSGreg Roach public function pendingChangesExist(): bool 615ade503dfSGreg Roach { 616ade503dfSGreg Roach return $this->tree && $this->tree->hasPendingEdit() && Auth::isModerator($this->tree); 617ade503dfSGreg Roach } 618ade503dfSGreg Roach 619ade503dfSGreg Roach /** 620ade503dfSGreg Roach * Generate a list of items for the main menu. 621ade503dfSGreg Roach * 622ade503dfSGreg Roach * @return Menu[] 623ade503dfSGreg Roach */ 624ade503dfSGreg Roach public function primaryMenu(): array 625ade503dfSGreg Roach { 6264ca7e03cSGreg Roach return app(ModuleService::class)->findByComponent('menu', $this->tree, Auth::user()) 627ade503dfSGreg Roach ->map(function (ModuleMenuInterface $menu): ?Menu { 628ade503dfSGreg Roach return $menu->getMenu($this->tree); 629ade503dfSGreg Roach }) 630ade503dfSGreg Roach ->filter() 631ade503dfSGreg Roach ->all(); 632ade503dfSGreg Roach } 633ade503dfSGreg Roach 634ade503dfSGreg Roach /** 635ade503dfSGreg Roach * Create the primary menu. 636ade503dfSGreg Roach * 637ade503dfSGreg Roach * @param Menu[] $menus 638ade503dfSGreg Roach * 639ade503dfSGreg Roach * @return string 640ade503dfSGreg Roach */ 641ade503dfSGreg Roach public function primaryMenuContent(array $menus): string 642ade503dfSGreg Roach { 643ade503dfSGreg Roach return implode('', array_map(function (Menu $menu): string { 644ade503dfSGreg Roach return $menu->bootstrap4(); 645ade503dfSGreg Roach }, $menus)); 646ade503dfSGreg Roach } 647ade503dfSGreg Roach 648ade503dfSGreg Roach /** 649ade503dfSGreg Roach * Generate a list of items for the user menu. 650ade503dfSGreg Roach * 651ade503dfSGreg Roach * @return Menu[] 652ade503dfSGreg Roach */ 653ade503dfSGreg Roach public function secondaryMenu(): array 654ade503dfSGreg Roach { 655ade503dfSGreg Roach return array_filter([ 656ade503dfSGreg Roach $this->menuPendingChanges(), 657ade503dfSGreg Roach $this->menuMyPages(), 658ade503dfSGreg Roach $this->menuThemes(), 659ade503dfSGreg Roach $this->menuLanguages(), 660ade503dfSGreg Roach $this->menuLogin(), 661ade503dfSGreg Roach $this->menuLogout(), 662ade503dfSGreg Roach ]); 663ade503dfSGreg Roach } 664ade503dfSGreg Roach 665ade503dfSGreg Roach /** 666ade503dfSGreg Roach * A list of CSS files to include for this page. 667ade503dfSGreg Roach * 668ade503dfSGreg Roach * @return string[] 669ade503dfSGreg Roach */ 670ade503dfSGreg Roach public function stylesheets(): array 671ade503dfSGreg Roach { 672ade503dfSGreg Roach return []; 673ade503dfSGreg Roach } 67449a243cbSGreg Roach} 675