18c2e8227SGreg Roach<?php 23976b470SGreg Roach 38c2e8227SGreg Roach/** 48c2e8227SGreg Roach * webtrees: online genealogy 51fe542e9SGreg Roach * Copyright (C) 2021 webtrees development team 68c2e8227SGreg Roach * This program is free software: you can redistribute it and/or modify 78c2e8227SGreg Roach * it under the terms of the GNU General Public License as published by 88c2e8227SGreg Roach * the Free Software Foundation, either version 3 of the License, or 98c2e8227SGreg Roach * (at your option) any later version. 108c2e8227SGreg Roach * This program is distributed in the hope that it will be useful, 118c2e8227SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 128c2e8227SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 138c2e8227SGreg Roach * GNU General Public License for more details. 148c2e8227SGreg Roach * You should have received a copy of the GNU General Public License 15*89f7189bSGreg Roach * along with this program. If not, see <https://www.gnu.org/licenses/>. 168c2e8227SGreg Roach */ 17fcfa147eSGreg Roach 18e7f56f2aSGreg Roachdeclare(strict_types=1); 19e7f56f2aSGreg Roach 2076692c8bSGreg Roachnamespace Fisharebest\Webtrees\Module; 2176692c8bSGreg Roach 220e62c4b8SGreg Roachuse Fisharebest\Webtrees\Auth; 231fe542e9SGreg Roachuse Fisharebest\Webtrees\Contracts\UserInterface; 240e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N; 250e62c4b8SGreg Roachuse Fisharebest\Webtrees\Individual; 260e62c4b8SGreg Roachuse Fisharebest\Webtrees\Module\InteractiveTree\TreeView; 27406008aaSGreg Roachuse Fisharebest\Webtrees\Registry; 284ca7e03cSGreg Roachuse Fisharebest\Webtrees\Services\ModuleService; 29e490cd80SGreg Roachuse Fisharebest\Webtrees\Tree; 301e7a7a28SGreg Roachuse Illuminate\Support\Str; 316ccdf4f0SGreg Roachuse Psr\Http\Message\ServerRequestInterface; 328c2e8227SGreg Roach 33406008aaSGreg Roachuse function extract; 34406008aaSGreg Roachuse function uasort; 35406008aaSGreg Roachuse function view; 36406008aaSGreg Roach 37406008aaSGreg Roachuse const EXTR_OVERWRITE; 38406008aaSGreg Roach 398c2e8227SGreg Roach/** 408c2e8227SGreg Roach * Class ChartsBlockModule 418c2e8227SGreg Roach */ 4237eb8894SGreg Roachclass ChartsBlockModule extends AbstractModule implements ModuleBlockInterface 43c1010edaSGreg Roach{ 4449a243cbSGreg Roach use ModuleBlockTrait; 4549a243cbSGreg Roach 46961ec755SGreg Roach /** 474ca7e03cSGreg Roach * @var ModuleService 484ca7e03cSGreg Roach */ 494ca7e03cSGreg Roach private $module_service; 504ca7e03cSGreg Roach 514ca7e03cSGreg Roach /** 524ca7e03cSGreg Roach * ChartsBlockModule constructor. 534ca7e03cSGreg Roach * 544ca7e03cSGreg Roach * @param ModuleService $module_service 554ca7e03cSGreg Roach */ 565bdbe281SGreg Roach public function __construct(ModuleService $module_service) 575bdbe281SGreg Roach { 584ca7e03cSGreg Roach $this->module_service = $module_service; 594ca7e03cSGreg Roach } 604ca7e03cSGreg Roach 614ca7e03cSGreg Roach /** 620cfd6963SGreg Roach * How should this module be identified in the control panel, etc.? 63961ec755SGreg Roach * 64961ec755SGreg Roach * @return string 65961ec755SGreg Roach */ 6649a243cbSGreg Roach public function title(): string 67c1010edaSGreg Roach { 68bbb76c12SGreg Roach /* I18N: Name of a module/block */ 69bbb76c12SGreg Roach return I18N::translate('Charts'); 708c2e8227SGreg Roach } 718c2e8227SGreg Roach 72961ec755SGreg Roach /** 73961ec755SGreg Roach * A sentence describing what this module does. 74961ec755SGreg Roach * 75961ec755SGreg Roach * @return string 76961ec755SGreg Roach */ 7749a243cbSGreg Roach public function description(): string 78c1010edaSGreg Roach { 79bbb76c12SGreg Roach /* I18N: Description of the “Charts” module */ 80bbb76c12SGreg Roach return I18N::translate('An alternative way to display charts.'); 818c2e8227SGreg Roach } 828c2e8227SGreg Roach 8376692c8bSGreg Roach /** 8476692c8bSGreg Roach * Generate the HTML content of this block. 8576692c8bSGreg Roach * 86e490cd80SGreg Roach * @param Tree $tree 8776692c8bSGreg Roach * @param int $block_id 883caaa4d2SGreg Roach * @param string $context 893caaa4d2SGreg Roach * @param string[] $config 9076692c8bSGreg Roach * 9176692c8bSGreg Roach * @return string 9276692c8bSGreg Roach */ 933caaa4d2SGreg Roach public function getBlock(Tree $tree, int $block_id, string $context, array $config = []): string 94c1010edaSGreg Roach { 95e490cd80SGreg Roach $PEDIGREE_ROOT_ID = $tree->getPreference('PEDIGREE_ROOT_ID'); 961fe542e9SGreg Roach $gedcomid = $tree->getUserPreference(Auth::user(), UserInterface::PREF_TREE_ACCOUNT_XREF); 97575707d1SGreg Roach $default_xref = $gedcomid ?: $PEDIGREE_ROOT_ID; 988c2e8227SGreg Roach 99e2a378d3SGreg Roach $type = $this->getBlockSetting($block_id, 'type', 'pedigree'); 100575707d1SGreg Roach $xref = $this->getBlockSetting($block_id, 'pid', $default_xref); 1018c2e8227SGreg Roach 1023caaa4d2SGreg Roach extract($config, EXTR_OVERWRITE); 1038c2e8227SGreg Roach 1046b9cb339SGreg Roach $individual = Registry::individualFactory()->make($xref, $tree); 1058c2e8227SGreg Roach 10649a243cbSGreg Roach $title = $this->title(); 1078c2e8227SGreg Roach 108575707d1SGreg Roach if ($individual instanceof Individual) { 1098c2e8227SGreg Roach switch ($type) { 110677aaceaSGreg Roach default: 1118c2e8227SGreg Roach case 'pedigree': 112ed9ba438SGreg Roach $module = $this->module_service->findByInterface(PedigreeChartModule::class)->first(); 113406008aaSGreg Roach if ($module instanceof PedigreeChartModule) { 114575707d1SGreg Roach $title = $module->chartTitle($individual); 115575707d1SGreg Roach $chart_url = $module->chartUrl($individual, [ 1169b5537c3SGreg Roach 'ajax' => true, 11702fe1c37SGreg Roach 'generations' => 3, 11871378461SGreg Roach 'layout' => PedigreeChartModule::STYLE_RIGHT, 11902fe1c37SGreg Roach ]); 120147e99aaSGreg Roach $content = view('modules/charts/chart', [ 12102fe1c37SGreg Roach 'block_id' => $block_id, 12202fe1c37SGreg Roach 'chart_url' => $chart_url, 12341f309deSGreg Roach 'class' => 'wt-chart-pedigree', 12402fe1c37SGreg Roach ]); 125406008aaSGreg Roach } else { 126406008aaSGreg Roach $title = I18N::translate('Pedigree'); 127406008aaSGreg Roach $content = I18N::translate('The module “%s” has been disabled.', $title); 128406008aaSGreg Roach } 1298c2e8227SGreg Roach break; 130677aaceaSGreg Roach 1318c2e8227SGreg Roach case 'descendants': 132ed9ba438SGreg Roach $module = $this->module_service->findByInterface(DescendancyChartModule::class)->first(); 133406008aaSGreg Roach 134406008aaSGreg Roach if ($module instanceof DescendancyChartModule) { 135575707d1SGreg Roach $title = $module->chartTitle($individual); 136575707d1SGreg Roach $chart_url = $module->chartUrl($individual, [ 1379b5537c3SGreg Roach 'ajax' => true, 13802fe1c37SGreg Roach 'generations' => 2, 1390f1e0f10SGreg Roach 'chart_style' => DescendancyChartModule::CHART_STYLE_TREE, 14002fe1c37SGreg Roach ]); 141147e99aaSGreg Roach $content = view('modules/charts/chart', [ 14202fe1c37SGreg Roach 'block_id' => $block_id, 14302fe1c37SGreg Roach 'chart_url' => $chart_url, 14441f309deSGreg Roach 'class' => 'wt-chart-descendants', 14502fe1c37SGreg Roach ]); 146406008aaSGreg Roach } else { 147406008aaSGreg Roach $title = I18N::translate('Descendants'); 148406008aaSGreg Roach $content = I18N::translate('The module “%s” has been disabled.', $title); 149406008aaSGreg Roach } 150406008aaSGreg Roach 1518c2e8227SGreg Roach break; 152677aaceaSGreg Roach 1538c2e8227SGreg Roach case 'hourglass': 154ed9ba438SGreg Roach $module = $this->module_service->findByInterface(HourglassChartModule::class)->first(); 155406008aaSGreg Roach 156406008aaSGreg Roach if ($module instanceof HourglassChartModule) { 157575707d1SGreg Roach $title = $module->chartTitle($individual); 158575707d1SGreg Roach $chart_url = $module->chartUrl($individual, [ 1599b5537c3SGreg Roach 'ajax' => true, 16002fe1c37SGreg Roach 'generations' => 2, 16102fe1c37SGreg Roach ]); 162147e99aaSGreg Roach $content = view('modules/charts/chart', [ 16302fe1c37SGreg Roach 'block_id' => $block_id, 16402fe1c37SGreg Roach 'chart_url' => $chart_url, 16541f309deSGreg Roach 'class' => 'wt-chart-hourglass', 16602fe1c37SGreg Roach ]); 167406008aaSGreg Roach } else { 168406008aaSGreg Roach $title = I18N::translate('Hourglass chart'); 169406008aaSGreg Roach $content = I18N::translate('The module “%s” has been disabled.', $title); 170406008aaSGreg Roach } 1718c2e8227SGreg Roach break; 172677aaceaSGreg Roach 1738c2e8227SGreg Roach case 'treenav': 17441f309deSGreg Roach $module = $this->module_service->findByInterface(InteractiveTreeModule::class)->first(); 175406008aaSGreg Roach 176406008aaSGreg Roach if ($module instanceof InteractiveTreeModule) { 177575707d1SGreg Roach $title = I18N::translate('Interactive tree of %s', $individual->fullName()); 17859f2f229SGreg Roach $tv = new TreeView(); 179575707d1SGreg Roach [$html, $js] = $tv->drawViewport($individual, 2); 180575707d1SGreg Roach $content = $html . '<script>' . $js . '</script>'; 181406008aaSGreg Roach } else { 182406008aaSGreg Roach $title = I18N::translate('Interactive tree'); 183406008aaSGreg Roach $content = I18N::translate('The module “%s” has been disabled.', $title); 184406008aaSGreg Roach } 185406008aaSGreg Roach 1868c2e8227SGreg Roach break; 1878c2e8227SGreg Roach } 1888c2e8227SGreg Roach } else { 1896e7bf391SGreg Roach $content = I18N::translate('You must select an individual and a chart type in the block preferences'); 1908c2e8227SGreg Roach } 1918c2e8227SGreg Roach 1923caaa4d2SGreg Roach if ($context !== self::CONTEXT_EMBED) { 193147e99aaSGreg Roach return view('modules/block-template', [ 1941e7a7a28SGreg Roach 'block' => Str::kebab($this->name()), 1959c6524dcSGreg Roach 'id' => $block_id, 1963caaa4d2SGreg Roach 'config_url' => $this->configUrl($tree, $context, $block_id), 1973f385873SGreg Roach 'title' => $title, 1989c6524dcSGreg Roach 'content' => $content, 1999c6524dcSGreg Roach ]); 2008c2e8227SGreg Roach } 201b2ce94c6SRico Sonntag 202b2ce94c6SRico Sonntag return $content; 2038c2e8227SGreg Roach } 2048c2e8227SGreg Roach 2053caaa4d2SGreg Roach /** 2063caaa4d2SGreg Roach * Should this block load asynchronously using AJAX? 2073caaa4d2SGreg Roach * 2083caaa4d2SGreg Roach * Simple blocks are faster in-line, more complex ones can be loaded later. 2093caaa4d2SGreg Roach * 2103caaa4d2SGreg Roach * @return bool 2113caaa4d2SGreg Roach */ 212c1010edaSGreg Roach public function loadAjax(): bool 213c1010edaSGreg Roach { 2148c2e8227SGreg Roach return true; 2158c2e8227SGreg Roach } 2168c2e8227SGreg Roach 2173caaa4d2SGreg Roach /** 2183caaa4d2SGreg Roach * Can this block be shown on the user’s home page? 2193caaa4d2SGreg Roach * 2203caaa4d2SGreg Roach * @return bool 2213caaa4d2SGreg Roach */ 222c1010edaSGreg Roach public function isUserBlock(): bool 223c1010edaSGreg Roach { 2248c2e8227SGreg Roach return true; 2258c2e8227SGreg Roach } 2268c2e8227SGreg Roach 2273caaa4d2SGreg Roach /** 2283caaa4d2SGreg Roach * Can this block be shown on the tree’s home page? 2293caaa4d2SGreg Roach * 2303caaa4d2SGreg Roach * @return bool 2313caaa4d2SGreg Roach */ 23263276d8fSGreg Roach public function isTreeBlock(): bool 233c1010edaSGreg Roach { 2348c2e8227SGreg Roach return true; 2358c2e8227SGreg Roach } 2368c2e8227SGreg Roach 23776692c8bSGreg Roach /** 238a45f9889SGreg Roach * Update the configuration for a block. 239a45f9889SGreg Roach * 2406ccdf4f0SGreg Roach * @param ServerRequestInterface $request 241a45f9889SGreg Roach * @param int $block_id 242a45f9889SGreg Roach * 243a45f9889SGreg Roach * @return void 244a45f9889SGreg Roach */ 2456ccdf4f0SGreg Roach public function saveBlockConfiguration(ServerRequestInterface $request, int $block_id): void 246a45f9889SGreg Roach { 247b46c87bdSGreg Roach $params = (array) $request->getParsedBody(); 248b46c87bdSGreg Roach 249b46c87bdSGreg Roach $this->setBlockSetting($block_id, 'type', $params['type'] ?? 'pedigree'); 250b46c87bdSGreg Roach $this->setBlockSetting($block_id, 'pid', $params['xref'] ?? ''); 251a45f9889SGreg Roach } 252a45f9889SGreg Roach 253a45f9889SGreg Roach /** 25476692c8bSGreg Roach * An HTML form to edit block settings 25576692c8bSGreg Roach * 256e490cd80SGreg Roach * @param Tree $tree 25776692c8bSGreg Roach * @param int $block_id 258a9430be8SGreg Roach * 2593caaa4d2SGreg Roach * @return string 26076692c8bSGreg Roach */ 2613caaa4d2SGreg Roach public function editBlockConfiguration(Tree $tree, int $block_id): string 262c1010edaSGreg Roach { 263e490cd80SGreg Roach $PEDIGREE_ROOT_ID = $tree->getPreference('PEDIGREE_ROOT_ID'); 2641fe542e9SGreg Roach $gedcomid = $tree->getUserPreference(Auth::user(), UserInterface::PREF_TREE_ACCOUNT_XREF); 265575707d1SGreg Roach $default_xref = $gedcomid ?: $PEDIGREE_ROOT_ID; 2668c2e8227SGreg Roach 267e2a378d3SGreg Roach $type = $this->getBlockSetting($block_id, 'type', 'pedigree'); 268575707d1SGreg Roach $xref = $this->getBlockSetting($block_id, 'pid', $default_xref); 2698c2e8227SGreg Roach 27013abd6f3SGreg Roach $charts = [ 271fddfbb14SGreg Roach 'pedigree' => I18N::translate('Pedigree'), 272fddfbb14SGreg Roach 'descendants' => I18N::translate('Descendants'), 273fddfbb14SGreg Roach 'hourglass' => I18N::translate('Hourglass chart'), 274fddfbb14SGreg Roach 'treenav' => I18N::translate('Interactive tree'), 27513abd6f3SGreg Roach ]; 276fddfbb14SGreg Roach uasort($charts, 'Fisharebest\Webtrees\I18N::strcasecmp'); 277fddfbb14SGreg Roach 2786b9cb339SGreg Roach $individual = Registry::individualFactory()->make($xref, $tree); 279c385536dSGreg Roach 2803caaa4d2SGreg Roach return view('modules/charts/config', [ 281c385536dSGreg Roach 'charts' => $charts, 282c385536dSGreg Roach 'individual' => $individual, 283e490cd80SGreg Roach 'tree' => $tree, 284c385536dSGreg Roach 'type' => $type, 285c385536dSGreg Roach ]); 2868c2e8227SGreg Roach } 2878c2e8227SGreg Roach} 288