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\Exceptions\IndividualAccessDeniedException; 21use Fisharebest\Webtrees\Exceptions\IndividualNotFoundException; 22use Fisharebest\Webtrees\Gedcom; 23use Fisharebest\Webtrees\I18N; 24use Fisharebest\Webtrees\Individual; 25use Fisharebest\Webtrees\Menu; 26use Fisharebest\Webtrees\Module\InteractiveTree\TreeView; 27use Fisharebest\Webtrees\Tree; 28use Fisharebest\Webtrees\Webtrees; 29use Symfony\Component\HttpFoundation\Request; 30use Symfony\Component\HttpFoundation\Response; 31 32/** 33 * Class InteractiveTreeModule 34 * 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 35 */ 36class InteractiveTreeModule extends AbstractModule implements ModuleInterface, ModuleChartInterface, ModuleTabInterface 37{ 38 use ModuleChartTrait; 39 use ModuleTabTrait; 40 41 /** 42 * How should this module be labelled on tabs, menus, etc.? 43 * 44 * @return string 45 */ 46 public function title(): string 47 { 48 /* I18N: Name of a module */ 49 return I18N::translate('Interactive tree'); 50 } 51 52 /** 53 * A sentence describing what this module does. 54 * 55 * @return string 56 */ 57 public function description(): string 58 { 59 /* I18N: Description of the “Interactive tree” module */ 60 return I18N::translate('An interactive tree, showing all the ancestors and descendants of an individual.'); 61 } 62 63 /** 64 * The default position for this tab. It can be changed in the control panel. 65 * 66 * @return int 67 */ 68 public function defaultTabOrder(): int 69 { 70 return 9; 71 } 72 73 /** {@inheritdoc} */ 74 public function getTabContent(Individual $individual): string 75 { 76 $treeview = new TreeView('tvTab'); 77 [$html, $js] = $treeview->drawViewport($individual, 3); 78 79 return view('modules/tree/tab', [ 80 'html' => $html, 81 'js' => $js, 82 'treeview_css' => $this->css(), 83 'treeview_js' => $this->js(), 84 ]); 85 } 86 87 /** 88 * @return string 89 */ 90 public function css(): string 91 { 92 return Webtrees::MODULES_PATH . $this->name() . '/css/treeview.css'; 93 } 94 95 /** 96 * @return string 97 */ 98 public function js(): string 99 { 100 return Webtrees::MODULES_PATH . $this->name() . '/js/treeview.js'; 101 } 102 103 /** {@inheritdoc} */ 104 public function hasTabContent(Individual $individual): bool 105 { 106 return true; 107 } 108 109 /** {@inheritdoc} */ 110 public function isGrayedOut(Individual $individual): bool 111 { 112 return false; 113 } 114 115 /** {@inheritdoc} */ 116 public function canLoadAjax(): bool 117 { 118 return true; 119 } 120 121 /** 122 * CSS class for the URL. 123 * 124 * @return string 125 */ 126 public function chartMenuClass(): string 127 { 128 return 'menu-chart-tree'; 129 } 130 131 /** 132 * Return a menu item for this chart - for use in individual boxes. 133 * 134 * @param Individual $individual 135 * 136 * @return Menu|null 137 */ 138 public function chartBoxMenu(Individual $individual): ?Menu 139 { 140 return $this->chartMenu($individual); 141 } 142 143 /** 144 * The title for a specific instance of this chart. 145 * 146 * @param Individual $individual 147 * 148 * @return string 149 */ 150 public function chartTitle(Individual $individual): string 151 { 152 /* I18N: %s is an individual’s name */ 153 return I18N::translate('Interactive tree of %s', $individual->getFullName()); 154 } 155 156 /** 157 * The URL for this chart. 158 * 159 * @param Individual $individual 160 * @param string[] $parameters 161 * 162 * @return string 163 */ 164 public function chartUrl(Individual $individual, array $parameters = []): string 165 { 166 return route('module', [ 167 'module' => $this->name(), 168 'action' => 'Treeview', 169 'xref' => $individual->xref(), 170 'ged' => $individual->tree()->name(), 171 ] + $parameters); 172 } 173 174 /** 175 * @param Request $request 176 * @param Tree $tree 177 * 178 * @return Response 179 */ 180 public function getTreeviewAction(Request $request, Tree $tree): Response 181 { 182 $xref = $request->get('xref', ''); 183 184 $individual = Individual::getInstance($xref, $tree); 185 186 if ($individual === null) { 187 throw new IndividualNotFoundException(); 188 } 189 190 if (!$individual->canShow()) { 191 throw new IndividualAccessDeniedException(); 192 } 193 194 $tv = new TreeView('tv'); 195 196 [$html, $js] = $tv->drawViewport($individual, 4); 197 198 $title = I18N::translate('Interactive tree of %s', $individual->getFullName()); 199 200 return $this->viewResponse('interactive-tree-page', [ 201 'title' => $title, 202 'individual' => $individual, 203 'js' => $js, 204 'html' => $html, 205 'tree' => $tree, 206 ]); 207 } 208 209 /** 210 * @param Request $request 211 * @param Tree $tree 212 * 213 * @return Response 214 */ 215 public function getDetailsAction(Request $request, Tree $tree): Response 216 { 217 $pid = $request->get('pid', Gedcom::REGEX_XREF); 218 $individual = Individual::getInstance($pid, $tree); 219 220 if ($individual === null) { 221 throw new IndividualNotFoundException(); 222 } 223 224 if (!$individual->canShow()) { 225 throw new IndividualAccessDeniedException(); 226 } 227 228 $instance = $request->get('instance', ''); 229 $treeview = new TreeView($instance); 230 231 return new Response($treeview->getDetails($individual)); 232 } 233 234 /** 235 * @param Request $request 236 * @param Tree $tree 237 * 238 * @return Response 239 */ 240 public function getPersonsAction(Request $request, Tree $tree): Response 241 { 242 $q = $request->get('q', ''); 243 $instance = $request->get('instance', ''); 244 $treeview = new TreeView($instance); 245 246 return new Response($treeview->getPersons($tree, $q)); 247 } 248} 249