xref: /webtrees/app/Module/FrequentlyAskedQuestionsModule.php (revision 15d603e7c7c15d20f055d3d9c38d6b133453c5be)
18c2e8227SGreg Roach<?php
28c2e8227SGreg Roach/**
38c2e8227SGreg Roach * webtrees: online genealogy
46bdf7674SGreg Roach * Copyright (C) 2017 webtrees development team
58c2e8227SGreg Roach * This program is free software: you can redistribute it and/or modify
68c2e8227SGreg Roach * it under the terms of the GNU General Public License as published by
78c2e8227SGreg Roach * the Free Software Foundation, either version 3 of the License, or
88c2e8227SGreg Roach * (at your option) any later version.
98c2e8227SGreg Roach * This program is distributed in the hope that it will be useful,
108c2e8227SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of
118c2e8227SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
128c2e8227SGreg Roach * GNU General Public License for more details.
138c2e8227SGreg Roach * You should have received a copy of the GNU General Public License
148c2e8227SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>.
158c2e8227SGreg Roach */
1676692c8bSGreg Roachnamespace Fisharebest\Webtrees\Module;
1776692c8bSGreg Roach
180e62c4b8SGreg Roachuse Fisharebest\Webtrees\Auth;
19*15d603e7SGreg Roachuse Fisharebest\Webtrees\Bootstrap4;
200e62c4b8SGreg Roachuse Fisharebest\Webtrees\Controller\PageController;
210e62c4b8SGreg Roachuse Fisharebest\Webtrees\Database;
220e62c4b8SGreg Roachuse Fisharebest\Webtrees\Filter;
233d7a8a4cSGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsEdit;
240e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N;
250e62c4b8SGreg Roachuse Fisharebest\Webtrees\Menu;
260e62c4b8SGreg Roachuse Fisharebest\Webtrees\Module;
270e62c4b8SGreg Roachuse Fisharebest\Webtrees\Tree;
288c2e8227SGreg Roach
298c2e8227SGreg Roach/**
308c2e8227SGreg Roach * Class FrequentlyAskedQuestionsModule
318c2e8227SGreg Roach */
32e2a378d3SGreg Roachclass FrequentlyAskedQuestionsModule extends AbstractModule implements ModuleMenuInterface, ModuleConfigInterface {
338c2e8227SGreg Roach	/** {@inheritdoc} */
348c2e8227SGreg Roach	public function getTitle() {
358c2e8227SGreg Roach		return /* I18N: Name of a module. Abbreviation for “Frequently Asked Questions” */ I18N::translate('FAQ');
368c2e8227SGreg Roach	}
378c2e8227SGreg Roach
388c2e8227SGreg Roach	/** {@inheritdoc} */
398c2e8227SGreg Roach	public function getDescription() {
408c2e8227SGreg Roach		return /* I18N: Description of the “FAQ” module */ I18N::translate('A list of frequently asked questions and answers.');
418c2e8227SGreg Roach	}
428c2e8227SGreg Roach
4376692c8bSGreg Roach	/**
4476692c8bSGreg Roach	 * This is a general purpose hook, allowing modules to respond to routes
4576692c8bSGreg Roach	 * of the form module.php?mod=FOO&mod_action=BAR
4676692c8bSGreg Roach	 *
4776692c8bSGreg Roach	 * @param string $mod_action
4876692c8bSGreg Roach	 */
498c2e8227SGreg Roach	public function modAction($mod_action) {
508c2e8227SGreg Roach		switch ($mod_action) {
518c2e8227SGreg Roach		case 'admin_config':
528c2e8227SGreg Roach			$this->config();
538c2e8227SGreg Roach			break;
548c2e8227SGreg Roach		case 'admin_delete':
55b1d70009SGreg Roach			if (Auth::isAdmin()) {
568c2e8227SGreg Roach				$this->delete();
57b1d70009SGreg Roach			}
58b1d70009SGreg Roach			header('Location: ' . WT_BASE_URL . 'module.php?mod=faq&mod_action=admin_config');
598c2e8227SGreg Roach			break;
608c2e8227SGreg Roach		case 'admin_edit':
618c2e8227SGreg Roach			$this->edit();
628c2e8227SGreg Roach			break;
63b1d70009SGreg Roach		case 'admin_edit_save':
64b1d70009SGreg Roach			if (Auth::isAdmin()) {
65b1d70009SGreg Roach				$this->editSave();
66b1d70009SGreg Roach			}
67b1d70009SGreg Roach			header('Location: ' . WT_BASE_URL . 'module.php?mod=faq&mod_action=admin_config');
68b1d70009SGreg Roach			break;
698c2e8227SGreg Roach		case 'admin_movedown':
70b1d70009SGreg Roach			if (Auth::isAdmin()) {
718c2e8227SGreg Roach				$this->movedown();
72b1d70009SGreg Roach			}
73b1d70009SGreg Roach			header('Location: ' . WT_BASE_URL . 'module.php?mod=faq&mod_action=admin_config');
748c2e8227SGreg Roach			break;
758c2e8227SGreg Roach		case 'admin_moveup':
76b1d70009SGreg Roach			if (Auth::isAdmin()) {
778c2e8227SGreg Roach				$this->moveup();
78b1d70009SGreg Roach			}
79b1d70009SGreg Roach			header('Location: ' . WT_BASE_URL . 'module.php?mod=faq&mod_action=admin_config');
808c2e8227SGreg Roach			break;
818c2e8227SGreg Roach		case 'show':
828c2e8227SGreg Roach			$this->show();
838c2e8227SGreg Roach			break;
848c2e8227SGreg Roach		default:
858c2e8227SGreg Roach			http_response_code(404);
868c2e8227SGreg Roach		}
878c2e8227SGreg Roach	}
888c2e8227SGreg Roach
898c2e8227SGreg Roach	/** {@inheritdoc} */
908c2e8227SGreg Roach	public function getConfigLink() {
918c2e8227SGreg Roach		return 'module.php?mod=' . $this->getName() . '&amp;mod_action=admin_config';
928c2e8227SGreg Roach	}
938c2e8227SGreg Roach
948c2e8227SGreg Roach	/**
958c2e8227SGreg Roach	 * Action from the configuration page
968c2e8227SGreg Roach	 */
97b1d70009SGreg Roach	private function editSave() {
98b1d70009SGreg Roach		if (Filter::checkCsrf()) {
998c2e8227SGreg Roach			$block_id = Filter::postInteger('block_id');
1008c2e8227SGreg Roach			if ($block_id) {
1018c2e8227SGreg Roach				Database::prepare(
1028c2e8227SGreg Roach					"UPDATE `##block` SET gedcom_id = NULLIF(:tree_id, '0'), block_order = :block_order WHERE block_id = :block_id"
10313abd6f3SGreg Roach				)->execute([
1048c2e8227SGreg Roach					'tree_id'     => Filter::postInteger('gedcom_id'),
1058c2e8227SGreg Roach					'block_order' => Filter::postInteger('block_order'),
106cbc1590aSGreg Roach					'block_id'    => $block_id,
10713abd6f3SGreg Roach				]);
1088c2e8227SGreg Roach			} else {
1098c2e8227SGreg Roach				Database::prepare(
1108c2e8227SGreg Roach					"INSERT INTO `##block` (gedcom_id, module_name, block_order) VALUES (NULLIF(:tree_id, '0'), :module_name, :block_order)"
11113abd6f3SGreg Roach				)->execute([
1128c2e8227SGreg Roach					'tree_id'     => Filter::postInteger('gedcom_id'),
1138c2e8227SGreg Roach					'module_name' => $this->getName(),
1148c2e8227SGreg Roach					'block_order' => Filter::postInteger('block_order'),
11513abd6f3SGreg Roach				]);
1168c2e8227SGreg Roach				$block_id = Database::getInstance()->lastInsertId();
1178c2e8227SGreg Roach			}
118e2a378d3SGreg Roach			$this->setBlockSetting($block_id, 'header', Filter::post('header'));
119e2a378d3SGreg Roach			$this->setBlockSetting($block_id, 'faqbody', Filter::post('faqbody'));
1208c2e8227SGreg Roach
121c999a340SGreg Roach			$languages = Filter::postArray('lang');
122e2a378d3SGreg Roach			$this->setBlockSetting($block_id, 'languages', implode(',', $languages));
123b1d70009SGreg Roach		}
124b1d70009SGreg Roach	}
125b1d70009SGreg Roach
126b1d70009SGreg Roach	/**
127b1d70009SGreg Roach	 * Action from the configuration page
128b1d70009SGreg Roach	 */
129b1d70009SGreg Roach	private function edit() {
130b1d70009SGreg Roach		global $WT_TREE;
131b1d70009SGreg Roach
1328c2e8227SGreg Roach		$controller = new PageController;
133b1d70009SGreg Roach		$controller->restrictAccess(Auth::isAdmin());
134b1d70009SGreg Roach
135b1d70009SGreg Roach			$block_id = Filter::getInteger('block_id');
1368c2e8227SGreg Roach		if ($block_id) {
137b1783ef7SGreg Roach			$controller->setPageTitle(/* I18N: FAQ = “Frequently Asked Question” */ I18N::translate('Edit the FAQ'));
138e2a378d3SGreg Roach			$header      = $this->getBlockSetting($block_id, 'header');
139e2a378d3SGreg Roach			$faqbody     = $this->getBlockSetting($block_id, 'faqbody');
1408c2e8227SGreg Roach			$block_order = Database::prepare(
1418c2e8227SGreg Roach				"SELECT block_order FROM `##block` WHERE block_id = :block_id"
14213abd6f3SGreg Roach			)->execute(['block_id' => $block_id])->fetchOne();
1438c2e8227SGreg Roach			$gedcom_id   = Database::prepare(
1448c2e8227SGreg Roach				"SELECT gedcom_id FROM `##block` WHERE block_id = :block_id"
14513abd6f3SGreg Roach			)->execute(['block_id' => $block_id])->fetchOne();
1468c2e8227SGreg Roach		} else {
147b1783ef7SGreg Roach			$controller->setPageTitle(/* I18N: FAQ = “Frequently Asked Question” */ I18N::translate('Add an FAQ'));
1488c2e8227SGreg Roach			$header      = '';
1498c2e8227SGreg Roach			$faqbody     = '';
1508c2e8227SGreg Roach			$block_order = Database::prepare(
1518c2e8227SGreg Roach				"SELECT IFNULL(MAX(block_order)+1, 0) FROM `##block` WHERE module_name = :module_name"
15213abd6f3SGreg Roach			)->execute(['module_name' => $this->getName()])->fetchOne();
15324ec66ceSGreg Roach			$gedcom_id   = $WT_TREE->getTreeId();
1548c2e8227SGreg Roach		}
1558c2e8227SGreg Roach		$controller->pageHeader();
1568c2e8227SGreg Roach		if (Module::getModuleByName('ckeditor')) {
1578c2e8227SGreg Roach			CkeditorModule::enableEditor($controller);
1588c2e8227SGreg Roach		}
1598c2e8227SGreg Roach
160*15d603e7SGreg Roach		echo Bootstrap4::breadcrumbs([
161*15d603e7SGreg Roach			'admin.php'                                                       => I18N::translate('Control panel'),
162*15d603e7SGreg Roach			'admin_modules.php'                                               => I18N::translate('Module administration'),
163*15d603e7SGreg Roach			'module.php?mod=' . $this->getName() . '&mod_action=admin_config' => $this->getTitle(),
164*15d603e7SGreg Roach		], $controller->getPageTitle());
1658c2e8227SGreg Roach		?>
1664d6c0a77SGreg Roach
167*15d603e7SGreg Roach		<h1><?= $controller->getPageTitle() ?></h1>
1684d6c0a77SGreg Roach
169*15d603e7SGreg Roach		<form name="faq" class="form-horizontal" method="post" action="module.php?mod=<?= $this->getName() ?>&amp;mod_action=admin_edit_save">
170*15d603e7SGreg Roach		<?= Filter::getCsrf() ?>
171*15d603e7SGreg Roach		<input type="hidden" name="block_id" value="<?= $block_id ?>">
172*15d603e7SGreg Roach
173*15d603e7SGreg Roach		<div class="row form-group">
174*15d603e7SGreg Roach			<label for="header" class="col-sm-3 col-form-label">
175564ae2d7SGreg Roach				<?= I18N::translate('Question') ?>
1764d6c0a77SGreg Roach			</label>
1774d6c0a77SGreg Roach
1784d6c0a77SGreg Roach			<div class="col-sm-9">
1794d6c0a77SGreg Roach				<input type="text" class="form-control" name="header" id="header"
180564ae2d7SGreg Roach				       value="<?= Filter::escapeHtml($header) ?>">
1814d6c0a77SGreg Roach			</div>
1824d6c0a77SGreg Roach		</div>
1834d6c0a77SGreg Roach
184*15d603e7SGreg Roach		<div class="row form-group">
185*15d603e7SGreg Roach			<label for="faqbody" class="col-sm-3 col-form-label">
186564ae2d7SGreg Roach				<?= I18N::translate('Answer') ?>
1874d6c0a77SGreg Roach			</label>
1884d6c0a77SGreg Roach
1894d6c0a77SGreg Roach			<div class="col-sm-9">
190564ae2d7SGreg Roach				<textarea name="faqbody" id="faqbody" class="form-control html-edit" rows="10"><?= Filter::escapeHtml($faqbody) ?></textarea>
1914d6c0a77SGreg Roach			</div>
1924d6c0a77SGreg Roach		</div>
1934d6c0a77SGreg Roach
194*15d603e7SGreg Roach		<div class="row form-group">
195*15d603e7SGreg Roach			<label for="xref" class="col-sm-3 col-form-label">
196564ae2d7SGreg Roach				<?= /* I18N: Label for a configuration option */ I18N::translate('Show this block for which languages') ?>
1974d6c0a77SGreg Roach			</label>
1984d6c0a77SGreg Roach
1994d6c0a77SGreg Roach			<div class="col-sm-9">
200564ae2d7SGreg Roach				<?= FunctionsEdit::editLanguageCheckboxes('lang', explode(',', $this->getBlockSetting($block_id, 'languages'))) ?>
2014d6c0a77SGreg Roach			</div>
2024d6c0a77SGreg Roach		</div>
2034d6c0a77SGreg Roach
204*15d603e7SGreg Roach		<div class="row form-group">
205*15d603e7SGreg Roach			<label for="block_order" class="col-sm-3 col-form-label">
206564ae2d7SGreg Roach				<?= I18N::translate('Sort order') ?>
2074d6c0a77SGreg Roach			</label>
2084d6c0a77SGreg Roach
2094d6c0a77SGreg Roach			<div class="col-sm-9">
210564ae2d7SGreg Roach				<input type="text" name="block_order" id="block_order" class="form-control" value="<?= $block_order ?>">
2114d6c0a77SGreg Roach			</div>
2124d6c0a77SGreg Roach		</div>
2134d6c0a77SGreg Roach
214*15d603e7SGreg Roach		<div class="row form-group">
215*15d603e7SGreg Roach			<label for="gedcom_id" class="col-sm-3 col-form-label">
216564ae2d7SGreg Roach				<?= I18N::translate('Family tree') ?>
2174d6c0a77SGreg Roach			</label>
2184d6c0a77SGreg Roach
2194d6c0a77SGreg Roach			<div class="col-sm-9">
220*15d603e7SGreg Roach				<?= Bootstrap4::select(['' => I18N::translate('All')] + Tree::getIdList(), $gedcom_id, ['id' => 'gedcom_id', 'name' => 'gedcom_id']) ?>
2214d6c0a77SGreg Roach				<p class="small text-muted">
222564ae2d7SGreg Roach					<?= /* I18N: FAQ = “Frequently Asked Question” */ I18N::translate('An FAQ can be displayed on just one of the family trees, or on all the family trees.') ?>
2234d6c0a77SGreg Roach				</p>
2244d6c0a77SGreg Roach			</div>
2254d6c0a77SGreg Roach		</div>
2264d6c0a77SGreg Roach
227*15d603e7SGreg Roach		<div class="row form-group">
228*15d603e7SGreg Roach			<div class="offset-sm-3 col-sm-9">
2294d6c0a77SGreg Roach				<button type="submit" class="btn btn-primary">
2304d6c0a77SGreg Roach					<i class="fa fa-check"></i>
231564ae2d7SGreg Roach					<?= I18N::translate('save') ?>
2324d6c0a77SGreg Roach				</button>
2334d6c0a77SGreg Roach			</div>
2344d6c0a77SGreg Roach		</div>
2354d6c0a77SGreg Roach
2364d6c0a77SGreg Roach	</form>
2378c2e8227SGreg Roach	<?php
2388c2e8227SGreg Roach	}
2398c2e8227SGreg Roach
2408c2e8227SGreg Roach	/**
241b1783ef7SGreg Roach	 * Delete an FAQ.
2428c2e8227SGreg Roach	 */
2438c2e8227SGreg Roach	private function delete() {
2448c2e8227SGreg Roach		$block_id = Filter::getInteger('block_id');
2458c2e8227SGreg Roach
2468c2e8227SGreg Roach		Database::prepare(
2478c2e8227SGreg Roach			"DELETE FROM `##block_setting` WHERE block_id = :block_id"
24813abd6f3SGreg Roach		)->execute(['block_id' => $block_id]);
2498c2e8227SGreg Roach
2508c2e8227SGreg Roach		Database::prepare(
2518c2e8227SGreg Roach			"DELETE FROM `##block` WHERE block_id = :block_id"
25213abd6f3SGreg Roach		)->execute(['block_id' => $block_id]);
2538c2e8227SGreg Roach	}
2548c2e8227SGreg Roach
2558c2e8227SGreg Roach	/**
256b1783ef7SGreg Roach	 * Move an FAQ up the list.
2578c2e8227SGreg Roach	 */
2588c2e8227SGreg Roach	private function moveup() {
2598c2e8227SGreg Roach		$block_id = Filter::getInteger('block_id');
2608c2e8227SGreg Roach
2618c2e8227SGreg Roach		$block_order = Database::prepare(
2628c2e8227SGreg Roach			"SELECT block_order FROM `##block` WHERE block_id = :block_id"
26313abd6f3SGreg Roach		)->execute(['block_id' => $block_id])->fetchOne();
2648c2e8227SGreg Roach
2658c2e8227SGreg Roach		$swap_block = Database::prepare(
2668c2e8227SGreg Roach			"SELECT block_order, block_id" .
2678c2e8227SGreg Roach			" FROM `##block`" .
2688c2e8227SGreg Roach			" WHERE block_order = (" .
2698c2e8227SGreg Roach			"  SELECT MAX(block_order) FROM `##block` WHERE block_order < :block_order AND module_name = :module_name_1" .
2708c2e8227SGreg Roach			" ) AND module_name = :module_name_2" .
2718c2e8227SGreg Roach			" LIMIT 1"
27213abd6f3SGreg Roach		)->execute([
2738c2e8227SGreg Roach			'block_order'   => $block_order,
2748c2e8227SGreg Roach			'module_name_1' => $this->getName(),
275cbc1590aSGreg Roach			'module_name_2' => $this->getName(),
27613abd6f3SGreg Roach		])->fetchOneRow();
2778c2e8227SGreg Roach		if ($swap_block) {
2788c2e8227SGreg Roach			Database::prepare(
2798c2e8227SGreg Roach				"UPDATE `##block` SET block_order = :block_order WHERE block_id = :block_id"
28013abd6f3SGreg Roach			)->execute([
2818c2e8227SGreg Roach				'block_order' => $swap_block->block_order,
2828c2e8227SGreg Roach				'block_id'    => $block_id,
28313abd6f3SGreg Roach			]);
2848c2e8227SGreg Roach			Database::prepare(
2858c2e8227SGreg Roach				"UPDATE `##block` SET block_order = :block_order WHERE block_id = :block_id"
28613abd6f3SGreg Roach			)->execute([
2878c2e8227SGreg Roach				'block_order' => $block_order,
2888c2e8227SGreg Roach				'block_id'    => $swap_block->block_id,
28913abd6f3SGreg Roach			]);
2908c2e8227SGreg Roach		}
2918c2e8227SGreg Roach	}
2928c2e8227SGreg Roach
2938c2e8227SGreg Roach	/**
294b1783ef7SGreg Roach	 * Move an FAQ down the list.
2958c2e8227SGreg Roach	 */
2968c2e8227SGreg Roach	private function movedown() {
2978c2e8227SGreg Roach		$block_id = Filter::get('block_id');
2988c2e8227SGreg Roach
2998c2e8227SGreg Roach		$block_order = Database::prepare(
3008c2e8227SGreg Roach			"SELECT block_order FROM `##block` WHERE block_id = :block_id"
30113abd6f3SGreg Roach		)->execute([
3028c2e8227SGreg Roach			'block_id' => $block_id,
30313abd6f3SGreg Roach		])->fetchOne();
3048c2e8227SGreg Roach
3058c2e8227SGreg Roach		$swap_block = Database::prepare(
3068c2e8227SGreg Roach			"SELECT block_order, block_id" .
3078c2e8227SGreg Roach			" FROM `##block`" .
3088c2e8227SGreg Roach			" WHERE block_order=(" .
3098c2e8227SGreg Roach			"  SELECT MIN(block_order) FROM `##block` WHERE block_order > :block_order AND module_name = :module_name_1" .
3108c2e8227SGreg Roach			" ) AND module_name = :module_name_2" .
3118c2e8227SGreg Roach			" LIMIT 1"
31213abd6f3SGreg Roach		)->execute([
3138c2e8227SGreg Roach			'block_order'   => $block_order,
3148c2e8227SGreg Roach			'module_name_1' => $this->getName(),
3158c2e8227SGreg Roach			'module_name_2' => $this->getName(),
31613abd6f3SGreg Roach			])->fetchOneRow();
3178c2e8227SGreg Roach		if ($swap_block) {
3188c2e8227SGreg Roach			Database::prepare(
3198c2e8227SGreg Roach				"UPDATE `##block` SET block_order = :block_order WHERE block_id = :block_id"
32013abd6f3SGreg Roach			)->execute([
3218c2e8227SGreg Roach				'block_order' => $swap_block->block_order,
3228c2e8227SGreg Roach				'block_id'    => $block_id,
32313abd6f3SGreg Roach			]);
3248c2e8227SGreg Roach			Database::prepare(
3258c2e8227SGreg Roach				"UPDATE `##block` SET block_order = :block_order WHERE block_id = :block_id"
32613abd6f3SGreg Roach			)->execute([
3278c2e8227SGreg Roach				'block_order' => $block_order,
3288c2e8227SGreg Roach				'block_id'    => $swap_block->block_id,
32913abd6f3SGreg Roach			]);
3308c2e8227SGreg Roach		}
3318c2e8227SGreg Roach	}
3328c2e8227SGreg Roach
3338c2e8227SGreg Roach	/**
3348c2e8227SGreg Roach	 * Show a list of FAQs
3358c2e8227SGreg Roach	 */
3368c2e8227SGreg Roach	private function show() {
3374b9ff166SGreg Roach		global $controller, $WT_TREE;
3384b9ff166SGreg Roach
3398c2e8227SGreg Roach		$controller = new PageController;
3408c2e8227SGreg Roach		$controller
3418c2e8227SGreg Roach			->setPageTitle(I18N::translate('Frequently asked questions'))
3428c2e8227SGreg Roach			->pageHeader();
3438c2e8227SGreg Roach
3448c2e8227SGreg Roach		$faqs = Database::prepare(
3458c2e8227SGreg Roach			"SELECT block_id, bs1.setting_value AS header, bs2.setting_value AS body, bs3.setting_value AS languages" .
3468c2e8227SGreg Roach			" FROM `##block` b" .
3478c2e8227SGreg Roach			" JOIN `##block_setting` bs1 USING (block_id)" .
3488c2e8227SGreg Roach			" JOIN `##block_setting` bs2 USING (block_id)" .
3498c2e8227SGreg Roach			" JOIN `##block_setting` bs3 USING (block_id)" .
3508c2e8227SGreg Roach			" WHERE module_name = :module_name" .
3518c2e8227SGreg Roach			" AND bs1.setting_name = 'header'" .
3528c2e8227SGreg Roach			" AND bs2.setting_name = 'faqbody'" .
3538c2e8227SGreg Roach			" AND bs3.setting_name = 'languages'" .
3548c2e8227SGreg Roach			" AND IFNULL(gedcom_id, :tree_id_1) = :tree_id_2" .
3558c2e8227SGreg Roach			" ORDER BY block_order"
35613abd6f3SGreg Roach		)->execute([
3578c2e8227SGreg Roach			'module_name' => $this->getName(),
35824ec66ceSGreg Roach			'tree_id_1'   => $WT_TREE->getTreeId(),
35924ec66ceSGreg Roach			'tree_id_2'   => $WT_TREE->getTreeId(),
36013abd6f3SGreg Roach		])->fetchAll();
3618c2e8227SGreg Roach
362*15d603e7SGreg Roach		echo '<h2 class="wt-page-title">', I18N::translate('Frequently asked questions');
3634b9ff166SGreg Roach		if (Auth::isManager($WT_TREE)) {
3642a277e58SGreg Roach			echo ' — <a href="module.php?mod=', $this->getName(), '&amp;mod_action=admin_config">', I18N::translate('edit'), '</a>';
3658c2e8227SGreg Roach		}
3662a277e58SGreg Roach		echo '</h2>';
3678c2e8227SGreg Roach		$row_count = 0;
3688c2e8227SGreg Roach		echo '<table class="faq">';
3698c2e8227SGreg Roach		// List of titles
3708c2e8227SGreg Roach		foreach ($faqs as $id => $faq) {
3718c2e8227SGreg Roach			if (!$faq->languages || in_array(WT_LOCALE, explode(',', $faq->languages))) {
3728c2e8227SGreg Roach				$row_color = ($row_count % 2) ? 'odd' : 'even';
3738c2e8227SGreg Roach				// NOTE: Print the header of the current item
3748c2e8227SGreg Roach				echo '<tr class="', $row_color, '"><td style="padding: 5px;">';
3758c2e8227SGreg Roach				echo '<a href="#faq', $id, '">', $faq->header, '</a>';
3768c2e8227SGreg Roach				echo '</td></tr>';
3778c2e8227SGreg Roach				$row_count++;
3788c2e8227SGreg Roach			}
3798c2e8227SGreg Roach		}
3808c2e8227SGreg Roach		echo '</table><hr>';
3818c2e8227SGreg Roach		// Detailed entries
3828c2e8227SGreg Roach		foreach ($faqs as $id => $faq) {
3838c2e8227SGreg Roach			if (!$faq->languages || in_array(WT_LOCALE, explode(',', $faq->languages))) {
3848c2e8227SGreg Roach				echo '<div class="faq_title" id="faq', $id, '">', $faq->header;
3858c2e8227SGreg Roach				echo '<div class="faq_top faq_italic">';
3868c2e8227SGreg Roach				echo '<a href="#content">', I18N::translate('back to top'), '</a>';
3878c2e8227SGreg Roach				echo '</div>';
3888c2e8227SGreg Roach				echo '</div>';
3898c2e8227SGreg Roach				echo '<div class="faq_body">', substr($faq->body, 0, 1) == '<' ? $faq->body : nl2br($faq->body, false), '</div>';
3908c2e8227SGreg Roach				echo '<hr>';
3918c2e8227SGreg Roach			}
3928c2e8227SGreg Roach		}
3938c2e8227SGreg Roach	}
3948c2e8227SGreg Roach
3958c2e8227SGreg Roach	/**
3968c2e8227SGreg Roach	 * Provide a form to manage the FAQs.
3978c2e8227SGreg Roach	 */
3988c2e8227SGreg Roach	private function config() {
39924ec66ceSGreg Roach		global $WT_TREE;
40024ec66ceSGreg Roach
4018c2e8227SGreg Roach		$controller = new PageController;
4028c2e8227SGreg Roach		$controller
403da3772f8SJustCarmen			->restrictAccess(Auth::isAdmin())
4048c2e8227SGreg Roach			->setPageTitle(I18N::translate('Frequently asked questions'))
4058c2e8227SGreg Roach			->pageHeader();
4068c2e8227SGreg Roach
4078c2e8227SGreg Roach		$faqs = Database::prepare(
4088c2e8227SGreg Roach			"SELECT block_id, block_order, gedcom_id, bs1.setting_value AS header, bs2.setting_value AS faqbody" .
4098c2e8227SGreg Roach			" FROM `##block` b" .
4108c2e8227SGreg Roach			" JOIN `##block_setting` bs1 USING (block_id)" .
4118c2e8227SGreg Roach			" JOIN `##block_setting` bs2 USING (block_id)" .
4128c2e8227SGreg Roach			" WHERE module_name = :module_name" .
4138c2e8227SGreg Roach			" AND bs1.setting_name = 'header'" .
4148c2e8227SGreg Roach			" AND bs2.setting_name = 'faqbody'" .
4158c2e8227SGreg Roach			" AND IFNULL(gedcom_id, :tree_id_1) = :tree_id_2" .
4168c2e8227SGreg Roach			" ORDER BY block_order"
41713abd6f3SGreg Roach		)->execute([
4188c2e8227SGreg Roach			'module_name' => $this->getName(),
41924ec66ceSGreg Roach			'tree_id_1'   => $WT_TREE->getTreeId(),
42024ec66ceSGreg Roach			'tree_id_2'   => $WT_TREE->getTreeId(),
42113abd6f3SGreg Roach			])->fetchAll();
4228c2e8227SGreg Roach
4238c2e8227SGreg Roach		$min_block_order = Database::prepare(
424ee928960SGreg Roach			"SELECT MIN(block_order) FROM `##block` WHERE module_name = 'faq' AND (gedcom_id = :tree_id OR gedcom_id IS NULL)"
42513abd6f3SGreg Roach		)->execute([
4264d6c0a77SGreg Roach			'tree_id' => $WT_TREE->getTreeId(),
42713abd6f3SGreg Roach		])->fetchOne();
4288c2e8227SGreg Roach
4298c2e8227SGreg Roach		$max_block_order = Database::prepare(
430ee928960SGreg Roach			"SELECT MAX(block_order) FROM `##block` WHERE module_name = 'faq' AND (gedcom_id = :tree_id OR gedcom_id IS NULL)"
43113abd6f3SGreg Roach		)->execute([
4324d6c0a77SGreg Roach			'tree_id' => $WT_TREE->getTreeId(),
43313abd6f3SGreg Roach		])->fetchOne();
4348c2e8227SGreg Roach
435*15d603e7SGreg Roach		echo Bootstrap4::breadcrumbs([
436*15d603e7SGreg Roach			'admin.php'         => I18N::translate('Control panel'),
437*15d603e7SGreg Roach			'admin_modules.php' => I18N::translate('Module administration'),
438*15d603e7SGreg Roach		], $controller->getPageTitle());
4398c2e8227SGreg Roach		?>
440*15d603e7SGreg Roach
441*15d603e7SGreg Roach		<h1><?= $controller->getPageTitle() ?></h1>
4428c2e8227SGreg Roach		<p>
443564ae2d7SGreg Roach			<?= /* I18N: FAQ = “Frequently Asked Question” */ I18N::translate('FAQs are lists of questions and answers, which allow you to explain the site’s rules, policies, and procedures to your visitors. Questions are typically concerned with privacy, copyright, user-accounts, unsuitable content, requirement for source-citations, etc.') ?>
444564ae2d7SGreg Roach			<?= I18N::translate('You may use HTML to format the answer and to add links to other websites.') ?>
4458c2e8227SGreg Roach		</p>
446b1783ef7SGreg Roach
447b1783ef7SGreg Roach		<p>
44807231e86SGreg Roach			<form class="form form-inline">
44907231e86SGreg Roach				<label for="ged" class="sr-only">
450564ae2d7SGreg Roach					<?= I18N::translate('Family tree') ?>
45107231e86SGreg Roach				</label>
452564ae2d7SGreg Roach				<input type="hidden" name="mod" value="<?=  $this->getName() ?>">
45307231e86SGreg Roach				<input type="hidden" name="mod_action" value="admin_config">
454*15d603e7SGreg Roach				<?= Bootstrap4::select(Tree::getNameList(), $WT_TREE->getName(), ['id' => 'ged', 'name' => 'ged']) ?>
455564ae2d7SGreg Roach				<input type="submit" class="btn btn-primary" value="<?= I18N::translate('show') ?>">
45607231e86SGreg Roach			</form>
457b1783ef7SGreg Roach		</p>
45807231e86SGreg Roach
45907231e86SGreg Roach		<p>
460564ae2d7SGreg Roach			<a href="module.php?mod=<?= $this->getName() ?>&amp;mod_action=admin_edit" class="btn btn-default">
46107231e86SGreg Roach				<i class="fa fa-plus"></i>
462564ae2d7SGreg Roach				<?= /* I18N: FAQ = “Frequently Asked Question” */ I18N::translate('Add an FAQ') ?>
46307231e86SGreg Roach			</a>
46407231e86SGreg Roach		</p>
46507231e86SGreg Roach
4668c2e8227SGreg Roach		<?php
4674d6c0a77SGreg Roach		echo '<table class="table table-bordered">';
4688c2e8227SGreg Roach		foreach ($faqs as $faq) {
4698c2e8227SGreg Roach			// NOTE: Print the position of the current item
4708c2e8227SGreg Roach			echo '<tr class="faq_edit_pos"><td>';
4714d6c0a77SGreg Roach			echo I18N::translate('#%s', $faq->block_order + 1), ' ';
4723a7d762dSGreg Roach			if ($faq->gedcom_id === null) {
4738c2e8227SGreg Roach				echo I18N::translate('All');
4748c2e8227SGreg Roach			} else {
475f306ecacSDavid Drury				echo $WT_TREE->getTitleHtml();
4768c2e8227SGreg Roach			}
4778c2e8227SGreg Roach			echo '</td>';
4788c2e8227SGreg Roach			// NOTE: Print the edit options of the current item
4798c2e8227SGreg Roach			echo '<td>';
4808c2e8227SGreg Roach			if ($faq->block_order == $min_block_order) {
4818c2e8227SGreg Roach				echo '&nbsp;';
4828c2e8227SGreg Roach			} else {
4834d6c0a77SGreg Roach				echo '<a href="module.php?mod=', $this->getName(), '&amp;mod_action=admin_moveup&amp;block_id=', $faq->block_id, '"><i class="fa fa-arrow-up"></i></i> ', I18N::translate('Move up'), '</a>';
4848c2e8227SGreg Roach			}
4858c2e8227SGreg Roach			echo '</td><td>';
4868c2e8227SGreg Roach			if ($faq->block_order == $max_block_order) {
4878c2e8227SGreg Roach				echo '&nbsp;';
4888c2e8227SGreg Roach			} else {
4894d6c0a77SGreg Roach				echo '<a href="module.php?mod=', $this->getName(), '&amp;mod_action=admin_movedown&amp;block_id=', $faq->block_id, '"><i class="fa fa-arrow-down"></i></i> ', I18N::translate('Move down'), '</a>';
4908c2e8227SGreg Roach			}
4918c2e8227SGreg Roach			echo '</td><td>';
4924d6c0a77SGreg Roach			echo '<a href="module.php?mod=', $this->getName(), '&amp;mod_action=admin_edit&amp;block_id=', $faq->block_id, '"><i class="fa fa-pencil"></i> ', I18N::translate('Edit'), '</a>';
4938c2e8227SGreg Roach			echo '</td><td>';
494727fa558SGreg Roach			echo '<a href="module.php?mod=', $this->getName(), '&amp;mod_action=admin_delete&amp;block_id=', $faq->block_id, '" onclick="return confirm(\'', I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeHtml($faq->header)), '\');"><i class="fa fa-trash"></i> ', I18N::translate('Delete'), '</a>';
4958c2e8227SGreg Roach			echo '</td></tr>';
4968c2e8227SGreg Roach			// NOTE: Print the title text of the current item
4978c2e8227SGreg Roach			echo '<tr><td colspan="5">';
4988c2e8227SGreg Roach			echo '<div class="faq_edit_item">';
4998c2e8227SGreg Roach			echo '<div class="faq_edit_title">', $faq->header, '</div>';
5008c2e8227SGreg Roach			// NOTE: Print the body text of the current item
5018c2e8227SGreg Roach			echo '<div class="faq_edit_content">', substr($faq->faqbody, 0, 1) == '<' ? $faq->faqbody : nl2br($faq->faqbody, false), '</div></div></td></tr>';
5028c2e8227SGreg Roach		}
5038c2e8227SGreg Roach		echo '</table>';
5048c2e8227SGreg Roach	}
5058c2e8227SGreg Roach
5060ee13198SGreg Roach	/**
5070ee13198SGreg Roach	 * The user can re-order menus. Until they do, they are shown in this order.
5080ee13198SGreg Roach	 *
5090ee13198SGreg Roach	 * @return int
5100ee13198SGreg Roach	 */
5118c2e8227SGreg Roach	public function defaultMenuOrder() {
5128c2e8227SGreg Roach		return 40;
5138c2e8227SGreg Roach	}
5148c2e8227SGreg Roach
5150ee13198SGreg Roach	/**
5160ee13198SGreg Roach	 * A menu, to be added to the main application menu.
5170ee13198SGreg Roach	 *
5180ee13198SGreg Roach	 * @return Menu|null
5190ee13198SGreg Roach	 */
5208c2e8227SGreg Roach	public function getMenu() {
52124ec66ceSGreg Roach		global $WT_TREE;
52224ec66ceSGreg Roach
5238c2e8227SGreg Roach		$faqs = Database::prepare(
5242b6675d7SGreg Roach			"SELECT block_id FROM `##block`" .
5252b6675d7SGreg Roach			" JOIN `##block_setting` USING (block_id)" .
5262b6675d7SGreg Roach			" WHERE module_name = :module_name AND IFNULL(gedcom_id, :tree_id_1) = :tree_id_2" .
5272b6675d7SGreg Roach			" AND setting_name='languages' AND (setting_value LIKE CONCAT('%', :locale, '%') OR setting_value='')"
52813abd6f3SGreg Roach		)->execute([
5298c2e8227SGreg Roach			'module_name' => $this->getName(),
53024ec66ceSGreg Roach			'tree_id_1'   => $WT_TREE->getTreeId(),
53124ec66ceSGreg Roach			'tree_id_2'   => $WT_TREE->getTreeId(),
5322b6675d7SGreg Roach			'locale'      => WT_LOCALE,
53313abd6f3SGreg Roach		])->fetchAll();
5348c2e8227SGreg Roach
53538a9583bSGreg Roach		if ($faqs) {
536b1783ef7SGreg Roach			return new Menu($this->getTitle(), 'module.php?mod=faq&amp;mod_action=show', 'menu-help');
53738a9583bSGreg Roach		} else {
5388c2e8227SGreg Roach			return null;
5398c2e8227SGreg Roach		}
5408c2e8227SGreg Roach
5418c2e8227SGreg Roach	}
5428c2e8227SGreg Roach}
543