1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2018 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 ModuleTabInterface, ModuleChartInterface 37{ 38 /** {@inheritdoc} */ 39 public function getTitle(): string 40 { 41 /* I18N: Name of a module */ 42 return I18N::translate('Interactive tree'); 43 } 44 45 /** {@inheritdoc} */ 46 public function getDescription(): string 47 { 48 /* I18N: Description of the “Interactive tree” module */ 49 return I18N::translate('An interactive tree, showing all the ancestors and descendants of an individual.'); 50 } 51 52 /** {@inheritdoc} */ 53 public function defaultTabOrder(): int 54 { 55 return 68; 56 } 57 58 /** {@inheritdoc} */ 59 public function getTabContent(Individual $individual): string 60 { 61 $treeview = new TreeView('tvTab'); 62 [$html, $js] = $treeview->drawViewport($individual, 3); 63 64 return view('modules/tree/tab', [ 65 'html' => $html, 66 'js' => $js, 67 'treeview_css' => $this->css(), 68 'treeview_js' => $this->js(), 69 ]); 70 } 71 72 /** 73 * @return string 74 */ 75 public function css(): string 76 { 77 return Webtrees::MODULES_PATH . $this->getName() . '/css/treeview.css'; 78 } 79 80 /** 81 * @return string 82 */ 83 public function js(): string 84 { 85 return Webtrees::MODULES_PATH . $this->getName() . '/js/treeview.js'; 86 } 87 88 /** {@inheritdoc} */ 89 public function hasTabContent(Individual $individual): bool 90 { 91 return true; 92 } 93 94 /** {@inheritdoc} */ 95 public function isGrayedOut(Individual $individual): bool 96 { 97 return false; 98 } 99 100 /** {@inheritdoc} */ 101 public function canLoadAjax(): bool 102 { 103 return true; 104 } 105 106 /** 107 * Return a menu item for this chart. 108 * 109 * @param Individual $individual 110 * 111 * @return Menu|null 112 */ 113 public function getChartMenu(Individual $individual) 114 { 115 return new Menu( 116 $this->getTitle(), 117 route('module', [ 118 'module' => $this->getName(), 119 'action' => 'Treeview', 120 'xref' => $individual->xref(), 121 'ged' => $individual->tree()->name(), 122 ]), 123 'menu-chart-tree', 124 ['rel' => 'nofollow'] 125 ); 126 } 127 128 /** 129 * Return a menu item for this chart - for use in individual boxes. 130 * 131 * @param Individual $individual 132 * 133 * @return Menu|null 134 */ 135 public function getBoxChartMenu(Individual $individual) 136 { 137 return $this->getChartMenu($individual); 138 } 139 140 /** 141 * @param Request $request 142 * @param Tree $tree 143 * 144 * @return Response 145 */ 146 public function getTreeviewAction(Request $request, Tree $tree): Response 147 { 148 $xref = $request->get('xref', ''); 149 150 $individual = Individual::getInstance($xref, $tree); 151 152 if ($individual === null) { 153 throw new IndividualNotFoundException(); 154 } 155 156 if (!$individual->canShow()) { 157 throw new IndividualAccessDeniedException(); 158 } 159 160 $tv = new TreeView('tv'); 161 162 [$html, $js] = $tv->drawViewport($individual, 4); 163 164 $title = I18N::translate('Interactive tree of %s', $individual->getFullName()); 165 166 return $this->viewResponse('interactive-tree-page', [ 167 'title' => $title, 168 'individual' => $individual, 169 'js' => $js, 170 'html' => $html, 171 'tree' => $tree, 172 ]); 173 } 174 175 /** 176 * @param Request $request 177 * @param Tree $tree 178 * 179 * @return Response 180 */ 181 public function getDetailsAction(Request $request, Tree $tree): Response 182 { 183 $pid = $request->get('pid', Gedcom::REGEX_XREF); 184 $individual = Individual::getInstance($pid, $tree); 185 186 if ($individual === null) { 187 throw new IndividualNotFoundException(); 188 } 189 190 if (!$individual->canShow()) { 191 throw new IndividualAccessDeniedException(); 192 } 193 194 $instance = $request->get('instance', ''); 195 $treeview = new TreeView($instance); 196 197 return new Response($treeview->getDetails($individual)); 198 } 199 200 /** 201 * @param Request $request 202 * @param Tree $tree 203 * 204 * @return Response 205 */ 206 public function getPersonsAction(Request $request, Tree $tree): Response 207 { 208 $q = $request->get('q', ''); 209 $instance = $request->get('instance', ''); 210 $treeview = new TreeView($instance); 211 212 return new Response($treeview->getPersons($tree, $q)); 213 } 214} 215