xref: /webtrees/app/Module/InteractiveTreeModule.php (revision 25b2dde3e6093aac83cf209f5229274bb21fd313)
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 */
16namespace Fisharebest\Webtrees\Module;
17
18use Fisharebest\Webtrees\Exceptions\IndividualAccessDeniedException;
19use Fisharebest\Webtrees\Exceptions\IndividualNotFoundException;
20use Fisharebest\Webtrees\I18N;
21use Fisharebest\Webtrees\Individual;
22use Fisharebest\Webtrees\Menu;
23use Fisharebest\Webtrees\Module\InteractiveTree\TreeView;
24use Fisharebest\Webtrees\Tree;
25use Symfony\Component\HttpFoundation\Request;
26use Symfony\Component\HttpFoundation\Response;
27
28/**
29 * Class InteractiveTreeModule
30 * 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
31 */
32class InteractiveTreeModule extends AbstractModule implements ModuleTabInterface, ModuleChartInterface {
33	/** {@inheritdoc} */
34	public function getTitle() {
35		return /* I18N: Name of a module */
36			I18N::translate('Interactive tree');
37	}
38
39	/** {@inheritdoc} */
40	public function getDescription() {
41		return /* I18N: Description of the “Interactive tree” module */
42			I18N::translate('An interactive tree, showing all the ancestors and descendants of an individual.');
43	}
44
45	/** {@inheritdoc} */
46	public function defaultTabOrder() {
47		return 68;
48	}
49
50	/** {@inheritdoc} */
51	public function getTabContent(Individual $individual) {
52		$treeview = new TreeView('tvTab');
53		list($html, $js) = $treeview->drawViewport($individual, 3);
54
55		return view('modules/tree/tab', [
56			'html'         => $html,
57			'js'           => $js,
58			'treeview_css' => $this->css(),
59			'treeview_js'  => $this->js(),
60		]);
61	}
62
63	/**
64	 * @return string
65	 */
66	public function css(): string {
67		return WT_MODULES_DIR . $this->getName() . '/css/treeview.css';
68	}
69
70	/**
71	 * @return string
72	 */
73	public function js(): string {
74		return WT_MODULES_DIR . $this->getName() . '/js/treeview.js';
75	}
76
77	/** {@inheritdoc} */
78	public function hasTabContent(Individual $individual) {
79		return true;
80	}
81
82	/** {@inheritdoc} */
83	public function isGrayedOut(Individual $individual) {
84		return false;
85	}
86
87	/** {@inheritdoc} */
88	public function canLoadAjax() {
89		return true;
90	}
91
92	/**
93	 * Return a menu item for this chart.
94	 *
95	 * @param Individual $individual
96	 *
97	 * @return Menu|null
98	 */
99	public function getChartMenu(Individual $individual) {
100		return new Menu(
101			$this->getTitle(),
102			route('module', ['module' => $this->getName(), 'action' => 'Treeview', 'xref' => $individual->getXref(), 'ged' => $individual->getTree()->getName()]),
103			'menu-chart-tree',
104			['rel' => 'nofollow']
105		);
106	}
107
108	/**
109	 * Return a menu item for this chart - for use in individual boxes.
110	 *
111	 * @param Individual $individual
112	 *
113	 * @return Menu|null
114	 */
115	public function getBoxChartMenu(Individual $individual) {
116		return $this->getChartMenu($individual);
117	}
118
119	/**
120	 * @param Request $request
121	 *
122	 * @return Response
123	 */
124	public function getTreeviewAction(Request $request): Response {
125		/** @var Tree $tree */
126		$tree = $request->attributes->get('tree');
127
128		$xref = $request->get('xref');
129
130		$individual = Individual::getInstance($xref, $tree);
131		$tv         = new TreeView('tv');
132
133		list($html, $js) = $tv->drawViewport($individual, 4);
134
135		$title = I18N::translate('Interactive tree of %s', $individual->getFullName());
136
137		return $this->viewResponse('interactive-tree-page', [
138			'title'      => $title,
139			'individual' => $individual,
140			'js'         => $js,
141			'html'       => $html,
142			'tree'       => $tree,
143		]);
144	}
145
146	/**
147	 * @param Request $request
148	 *
149	 * @return Response
150	 */
151	public function getDetailsAction(Request $request): Response {
152		/** @var Tree $tree */
153		$tree = $request->attributes->get('tree');
154
155		$pid        = $request->get('pid', WT_REGEX_XREF);
156		$individual = Individual::getInstance($pid, $tree);
157
158		if ($individual === null) {
159			throw new IndividualNotFoundException;
160		}
161
162		if (!$individual->canShow()) {
163			throw new IndividualAccessDeniedException;
164		}
165
166		$instance = $request->get('instance');
167		$treeview = new TreeView($instance);
168
169		return new Response($treeview->getDetails($individual));
170	}
171
172	/**
173	 * @param Request $request
174	 *
175	 * @return Response
176	 */
177	public function getPersonsAction(Request $request): Response {
178		/** @var Tree $tree */
179		$tree = $request->attributes->get('tree');
180
181		$q  = $request->get('q');
182		$instance = $request->get('instance');
183		$treeview = new TreeView($instance);
184
185		return new Response($treeview->getPersons($tree, $q));
186	}
187}
188