1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2019 webtrees development team 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 15 */ 16declare(strict_types=1); 17 18namespace Fisharebest\Webtrees\Module; 19 20use Fisharebest\Webtrees\Auth; 21use Fisharebest\Webtrees\Exceptions\IndividualAccessDeniedException; 22use Fisharebest\Webtrees\Exceptions\IndividualNotFoundException; 23use Fisharebest\Webtrees\I18N; 24use Fisharebest\Webtrees\Individual; 25use Fisharebest\Webtrees\Menu; 26use Fisharebest\Webtrees\Module\InteractiveTree\TreeView; 27use Psr\Http\Message\ResponseInterface; 28use Psr\Http\Message\ServerRequestInterface; 29 30/** 31 * Class InteractiveTreeModule 32 * Tip : you could change the number of generations loaded before ajax calls both in individual page and in treeview page to optimize speed and server load 33 */ 34class InteractiveTreeModule extends AbstractModule implements ModuleChartInterface, ModuleTabInterface 35{ 36 use ModuleChartTrait; 37 use ModuleTabTrait; 38 39 /** 40 * How should this module be identified in the control panel, etc.? 41 * 42 * @return string 43 */ 44 public function title(): string 45 { 46 /* I18N: Name of a module */ 47 return I18N::translate('Interactive tree'); 48 } 49 50 /** 51 * A sentence describing what this module does. 52 * 53 * @return string 54 */ 55 public function description(): string 56 { 57 /* I18N: Description of the “Interactive tree” module */ 58 return I18N::translate('An interactive tree, showing all the ancestors and descendants of an individual.'); 59 } 60 61 /** 62 * The default position for this tab. It can be changed in the control panel. 63 * 64 * @return int 65 */ 66 public function defaultTabOrder(): int 67 { 68 return 7; 69 } 70 71 /** 72 * Generate the HTML content of this tab. 73 * 74 * @param Individual $individual 75 * 76 * @return string 77 */ 78 public function getTabContent(Individual $individual): string 79 { 80 $treeview = new TreeView('tvTab'); 81 82 [$html, $js] = $treeview->drawViewport($individual, 3); 83 84 return view('modules/interactive-tree/tab', [ 85 'html' => $html, 86 'js' => $js, 87 ]); 88 } 89 90 /** 91 * Is this tab empty? If so, we don't always need to display it. 92 * 93 * @param Individual $individual 94 * 95 * @return bool 96 */ 97 public function hasTabContent(Individual $individual): bool 98 { 99 return true; 100 } 101 102 /** 103 * A greyed out tab has no actual content, but may perhaps have 104 * options to create content. 105 * 106 * @param Individual $individual 107 * 108 * @return bool 109 */ 110 public function isGrayedOut(Individual $individual): bool 111 { 112 return false; 113 } 114 115 /** 116 * Can this tab load asynchronously? 117 * 118 * @return bool 119 */ 120 public function canLoadAjax(): bool 121 { 122 return true; 123 } 124 125 /** 126 * CSS class for the URL. 127 * 128 * @return string 129 */ 130 public function chartMenuClass(): string 131 { 132 return 'menu-chart-tree'; 133 } 134 135 /** 136 * Return a menu item for this chart - for use in individual boxes. 137 * 138 * @param Individual $individual 139 * 140 * @return Menu|null 141 */ 142 public function chartBoxMenu(Individual $individual): ?Menu 143 { 144 return $this->chartMenu($individual); 145 } 146 147 /** 148 * The title for a specific instance of this chart. 149 * 150 * @param Individual $individual 151 * 152 * @return string 153 */ 154 public function chartTitle(Individual $individual): string 155 { 156 /* I18N: %s is an individual’s name */ 157 return I18N::translate('Interactive tree of %s', $individual->fullName()); 158 } 159 160 /** 161 * The URL for this chart. 162 * 163 * @param Individual $individual 164 * @param string[] $parameters 165 * 166 * @return string 167 */ 168 public function chartUrl(Individual $individual, array $parameters = []): string 169 { 170 return route('module', [ 171 'module' => $this->name(), 172 'action' => 'Chart', 173 'xref' => $individual->xref(), 174 'ged' => $individual->tree()->name(), 175 ] + $parameters); 176 } 177 178 /** 179 * @param ServerRequestInterface $request 180 * 181 * @return ResponseInterface 182 */ 183 public function getChartAction(ServerRequestInterface $request): ResponseInterface 184 { 185 $tree = $request->getAttribute('tree'); 186 $user = $request->getAttribute('user'); 187 $xref = $request->getQueryParams()['xref']; 188 189 $individual = Individual::getInstance($xref, $tree); 190 191 Auth::checkIndividualAccess($individual); 192 Auth::checkComponentAccess($this, 'chart', $tree, $user); 193 194 $tv = new TreeView('tv'); 195 196 [$html, $js] = $tv->drawViewport($individual, 4); 197 198 return $this->viewResponse('modules/interactive-tree/page', [ 199 'html' => $html, 200 'individual' => $individual, 201 'js' => $js, 202 'title' => $this->chartTitle($individual), 203 'tree' => $tree, 204 ]); 205 } 206 207 /** 208 * @param ServerRequestInterface $request 209 * 210 * @return ResponseInterface 211 */ 212 public function getDetailsAction(ServerRequestInterface $request): ResponseInterface 213 { 214 $tree = $request->getAttribute('tree'); 215 $pid = $request->getQueryParams()['pid']; 216 $individual = Individual::getInstance($pid, $tree); 217 218 if ($individual === null) { 219 throw new IndividualNotFoundException(); 220 } 221 222 if (!$individual->canShow()) { 223 throw new IndividualAccessDeniedException(); 224 } 225 226 $instance = $request->getQueryParams()['instance']; 227 $treeview = new TreeView($instance); 228 229 return response($treeview->getDetails($individual)); 230 } 231 232 /** 233 * @param ServerRequestInterface $request 234 * 235 * @return ResponseInterface 236 */ 237 public function getPersonsAction(ServerRequestInterface $request): ResponseInterface 238 { 239 $tree = $request->getAttribute('tree'); 240 $q = $request->getQueryParams()['q']; 241 $instance = $request->getQueryParams()['instance']; 242 $treeview = new TreeView($instance); 243 244 return response($treeview->getPersons($tree, $q)); 245 } 246} 247