xref: /webtrees/app/Module/AlbumModule.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;
190e62c4b8SGreg Roachuse Fisharebest\Webtrees\Filter;
203d7a8a4cSGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsPrint;
210e62c4b8SGreg Roachuse Fisharebest\Webtrees\I18N;
220e62c4b8SGreg Roachuse Fisharebest\Webtrees\Media;
230e62c4b8SGreg Roachuse Fisharebest\Webtrees\Menu;
240e62c4b8SGreg Roachuse Fisharebest\Webtrees\Module;
250e62c4b8SGreg Roachuse Fisharebest\Webtrees\Theme;
268c2e8227SGreg Roach
278c2e8227SGreg Roach/**
288c2e8227SGreg Roach * Class AlbumModule
298c2e8227SGreg Roach */
30e2a378d3SGreg Roachclass AlbumModule extends AbstractModule implements ModuleTabInterface {
3176692c8bSGreg Roach	/** @var Media[] List of media objects. */
328c2e8227SGreg Roach	private $media_list;
338c2e8227SGreg Roach
3476692c8bSGreg Roach	/**
3576692c8bSGreg Roach	 * How should this module be labelled on tabs, menus, etc.?
3676692c8bSGreg Roach	 *
3776692c8bSGreg Roach	 * @return string
3876692c8bSGreg Roach	 */
398c2e8227SGreg Roach	public function getTitle() {
408c2e8227SGreg Roach		return /* I18N: Name of a module */ I18N::translate('Album');
418c2e8227SGreg Roach	}
428c2e8227SGreg Roach
4376692c8bSGreg Roach	/**
4476692c8bSGreg Roach	 * A sentence describing what this module does.
4576692c8bSGreg Roach	 *
4676692c8bSGreg Roach	 * @return string
4776692c8bSGreg Roach	 */
488c2e8227SGreg Roach	public function getDescription() {
498c2e8227SGreg Roach		return /* I18N: Description of the “Album” module */ I18N::translate('An alternative to the “media” tab, and an enhanced image viewer.');
508c2e8227SGreg Roach	}
518c2e8227SGreg Roach
5276692c8bSGreg Roach	/**
5376692c8bSGreg Roach	 * The user can re-arrange the tab order, but until they do, this
5476692c8bSGreg Roach	 * is the order in which tabs are shown.
5576692c8bSGreg Roach	 *
5676692c8bSGreg Roach	 * @return int
5776692c8bSGreg Roach	 */
588c2e8227SGreg Roach	public function defaultTabOrder() {
598c2e8227SGreg Roach		return 60;
608c2e8227SGreg Roach	}
618c2e8227SGreg Roach
6276692c8bSGreg Roach	/**
6376692c8bSGreg Roach	 * Is this tab empty? If so, we don't always need to display it.
6476692c8bSGreg Roach	 *
6576692c8bSGreg Roach	 * @return bool
6676692c8bSGreg Roach	 */
678c2e8227SGreg Roach	public function hasTabContent() {
684b9ff166SGreg Roach		global $WT_TREE;
694b9ff166SGreg Roach
704b9ff166SGreg Roach		return Auth::isEditor($WT_TREE) || $this->getMedia();
718c2e8227SGreg Roach	}
728c2e8227SGreg Roach
7376692c8bSGreg Roach	/**
7476692c8bSGreg Roach	 * A greyed out tab has no actual content, but may perhaps have
7576692c8bSGreg Roach	 * options to create content.
7676692c8bSGreg Roach	 *
7776692c8bSGreg Roach	 * @return bool
7876692c8bSGreg Roach	 */
798c2e8227SGreg Roach	public function isGrayedOut() {
80764a01d9SGreg Roach		return !$this->getMedia();
818c2e8227SGreg Roach	}
828c2e8227SGreg Roach
8376692c8bSGreg Roach	/**
8476692c8bSGreg Roach	 * Generate the HTML content of this tab.
8576692c8bSGreg Roach	 *
8676692c8bSGreg Roach	 * @return string
8776692c8bSGreg Roach	 */
888c2e8227SGreg Roach	public function getTabContent() {
898c2e8227SGreg Roach		global $WT_TREE, $controller;
908c2e8227SGreg Roach
918c2e8227SGreg Roach		$html = '<div id="' . $this->getName() . '_content">';
928c2e8227SGreg Roach		//Show Lightbox-Album header Links
934b9ff166SGreg Roach		if (Auth::isEditor($WT_TREE)) {
94*15d603e7SGreg Roach			$html .= '<table class="facts_table"><tr><td class="descriptionbox rela">';
9529bb8efbSGreg Roach			// Add a media object
964b9ff166SGreg Roach			if ($WT_TREE->getPreference('MEDIA_UPLOAD') >= Auth::accessLevel($WT_TREE)) {
978c2e8227SGreg Roach				$html .= '<span><a href="#" onclick="window.open(\'addmedia.php?action=showmediaform&linktoid=' . $controller->record->getXref() . '\', \'_blank\', \'resizable=1,scrollbars=1,top=50,height=780,width=600\');return false;">';
98*15d603e7SGreg Roach				$html .= '<img src="' . Theme::theme()->assetUrl() . 'images/image_add.png" id="head_icon" class="icon" title="' . I18N::translate('Add a media object') . '">';
9929bb8efbSGreg Roach				$html .= I18N::translate('Add a media object');
1008c2e8227SGreg Roach				$html .= '</a></span>';
1018c2e8227SGreg Roach				// Link to an existing item
1028c2e8227SGreg Roach				$html .= '<span><a href="#" onclick="window.open(\'inverselink.php?linktoid=' . $controller->record->getXref() . '&linkto=person\', \'_blank\', \'resizable=1,scrollbars=1,top=50,height=300,width=450\');">';
103*15d603e7SGreg Roach				$html .= '<img src="' . Theme::theme()->assetUrl() . 'images/image_link.png" id="head_icon" class="icon" title="' . I18N::translate('Link to an existing media object') . '">';
1048c2e8227SGreg Roach				$html .= I18N::translate('Link to an existing media object');
1058c2e8227SGreg Roach				$html .= '</a></span>';
1068c2e8227SGreg Roach			}
1074b9ff166SGreg Roach			if (Auth::isManager($WT_TREE) && $this->getMedia()) {
108*15d603e7SGreg Roach				$html .= '<span><a href="edit_interface.php?action=reorder_media&amp;ged=' . $controller->record->getTree()->getNameHtml() . '&amp;xref=' . $controller->record->getXref() . '">';
109*15d603e7SGreg Roach				$html .= '<img src="' . Theme::theme()->assetUrl() . 'images/images.png" id="head_icon" class="icon" title="' . I18N::translate('Re-order media') . '">';
1108c2e8227SGreg Roach				$html .= I18N::translate('Re-order media');
1118c2e8227SGreg Roach				$html .= '</a></span>';
1128c2e8227SGreg Roach			}
1138c2e8227SGreg Roach			$html .= '</td></tr></table>';
1148c2e8227SGreg Roach		}
1158c2e8227SGreg Roach
1168c2e8227SGreg Roach		// Used when sorting media on album tab page
1178c2e8227SGreg Roach		$html .= '<table class="facts_table"><tr><td class="facts_value">'; // one-cell table - for presentation only
1188c2e8227SGreg Roach		$html .= '<ul class="album-list">';
119764a01d9SGreg Roach		foreach ($this->getMedia() as $media) {
1208c2e8227SGreg Roach			//View Edit Menu ----------------------------------
1218c2e8227SGreg Roach
1228c2e8227SGreg Roach			//Get media item Notes
1238c2e8227SGreg Roach			$haystack = $media->getGedcom();
1248c2e8227SGreg Roach			$needle   = '1 NOTE';
1258c2e8227SGreg Roach			$before   = substr($haystack, 0, strpos($haystack, $needle));
1268c2e8227SGreg Roach			$after    = substr(strstr($haystack, $needle), strlen($needle));
1273d7a8a4cSGreg Roach			$notes    = FunctionsPrint::printFactNotes($before . $needle . $after, 1, true);
1288c2e8227SGreg Roach
1298c2e8227SGreg Roach			// Prepare Below Thumbnail  menu ----------------------------------------------------
1308c2e8227SGreg Roach			$menu = new Menu('<div style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap">' . $media->getFullName() . '</div>');
1318c2e8227SGreg Roach			$menu->addClass('', 'submenu');
1328c2e8227SGreg Roach
1338c2e8227SGreg Roach			// View Notes
1348c2e8227SGreg Roach			if (strpos($media->getGedcom(), "\n1 NOTE")) {
13513abd6f3SGreg Roach				$submenu = new Menu(I18N::translate('View the notes'), '#', '', [
136cdc90107SGreg Roach					'onclick' => 'modalNotes("' . Filter::escapeJs($notes) . '","' . I18N::translate('View the notes') . '"); return false;',
13713abd6f3SGreg Roach				]);
1387a6ee1acSGreg Roach				$submenu->addClass('submenuitem');
1398c2e8227SGreg Roach				$menu->addSubmenu($submenu);
1408c2e8227SGreg Roach			}
1418c2e8227SGreg Roach			//View Details
142cdc90107SGreg Roach			$submenu = new Menu(I18N::translate('View the details'), $media->getHtmlUrl());
1437a6ee1acSGreg Roach			$submenu->addClass('submenuitem');
1448c2e8227SGreg Roach			$menu->addSubmenu($submenu);
1458c2e8227SGreg Roach
1468c2e8227SGreg Roach			//View Sources
1478c2e8227SGreg Roach			foreach ($media->getFacts('SOUR') as $source_fact) {
1488c2e8227SGreg Roach				$source = $source_fact->getTarget();
1498c2e8227SGreg Roach				if ($source && $source->canShow()) {
1508c2e8227SGreg Roach					$submenu = new Menu(I18N::translate('Source') . ' – ' . $source->getFullName(), $source->getHtmlUrl());
1518c2e8227SGreg Roach					$submenu->addClass('submenuitem');
1528c2e8227SGreg Roach					$menu->addSubmenu($submenu);
1538c2e8227SGreg Roach				}
1548c2e8227SGreg Roach			}
1558c2e8227SGreg Roach
1564b9ff166SGreg Roach			if (Auth::isEditor($media->getTree())) {
1578c2e8227SGreg Roach				// Edit Media
15813abd6f3SGreg Roach				$submenu = new Menu(I18N::translate('Edit the media object'), '#', '', [
1593cf92ae2SGreg Roach					'onclick' => 'return window.open("addmedia.php?action=editmedia&pid=' . $media->getXref() . '", "_blank", edit_window_specs);',
16013abd6f3SGreg Roach				]);
1617a6ee1acSGreg Roach				$submenu->addClass('submenuitem');
1628c2e8227SGreg Roach				$menu->addSubmenu($submenu);
1638c2e8227SGreg Roach				if (Auth::isAdmin()) {
1648c2e8227SGreg Roach					if (Module::getModuleByName('GEDFact_assistant')) {
16513abd6f3SGreg Roach						$submenu = new Menu(I18N::translate('Manage the links'), '#', '', [
1663cf92ae2SGreg Roach							'onclick' => 'return window.open("inverselink.php?mediaid=' . $media->getXref() . '&linkto=manage", "_blank", find_window_specs);',
16713abd6f3SGreg Roach						]);
1687a6ee1acSGreg Roach						$submenu->addClass('submenuitem');
1698c2e8227SGreg Roach						$menu->addSubmenu($submenu);
1708c2e8227SGreg Roach					} else {
17113abd6f3SGreg Roach						$submenu = new Menu(I18N::translate('Link this media object to an individual'), '#', 'menu-obje-link-indi', [
1723cf92ae2SGreg Roach							'onclick' => 'return ilinkitem("' . $media->getXref() . '","person");',
17313abd6f3SGreg Roach						]);
1748c2e8227SGreg Roach						$submenu->addClass('submenuitem');
1758c2e8227SGreg Roach						$menu->addSubmenu($submenu);
1768c2e8227SGreg Roach
17713abd6f3SGreg Roach						$submenu = new Menu(I18N::translate('Link this media object to a family'), '#', 'menu-obje-link-fam', [
1783cf92ae2SGreg Roach							'onclick' => 'return ilinkitem("' . $media->getXref() . '","family");',
17913abd6f3SGreg Roach						]);
1808c2e8227SGreg Roach						$submenu->addClass('submenuitem');
1818c2e8227SGreg Roach						$menu->addSubmenu($submenu);
1828c2e8227SGreg Roach
18313abd6f3SGreg Roach						$submenu = new Menu(I18N::translate('Link this media object to a source'), '#', 'menu-obje-link-sour', [
1843cf92ae2SGreg Roach							'onclick' => 'return ilinkitem("' . $media->getXref() . '","source");',
18513abd6f3SGreg Roach						]);
1868c2e8227SGreg Roach						$submenu->addClass('submenuitem');
1878c2e8227SGreg Roach						$menu->addSubmenu($submenu);
1888c2e8227SGreg Roach					}
18913abd6f3SGreg Roach					$submenu = new Menu(I18N::translate('Unlink the media object'), '#', '', [
1903cf92ae2SGreg Roach						'onclick' => 'return unlink_media("' . I18N::translate('Are you sure you want to remove links to this media object?') . '", "' . $controller->record->getXref() . '", "' . $media->getXref() . '");',
19113abd6f3SGreg Roach					]);
1927a6ee1acSGreg Roach					$submenu->addClass('submenuitem');
1938c2e8227SGreg Roach					$menu->addSubmenu($submenu);
1948c2e8227SGreg Roach				}
1958c2e8227SGreg Roach			}
1968c2e8227SGreg Roach			$html .= '<li class="album-list-item">';
1978c2e8227SGreg Roach			$html .= '<div class="album-image">' . $media->displayImage() . '</div>';
198*15d603e7SGreg Roach			$html .= '<div class="album-title">' . $menu->bootstrap4() . '</div>';
1998c2e8227SGreg Roach			$html .= '</li>';
2008c2e8227SGreg Roach		}
2018c2e8227SGreg Roach		$html .= '</ul>';
2028c2e8227SGreg Roach		$html .= '</td></tr></table>';
203*15d603e7SGreg Roach		$html .= '</div>';
204cbc1590aSGreg Roach
2058c2e8227SGreg Roach		return $html;
2068c2e8227SGreg Roach	}
2078c2e8227SGreg Roach
2088c2e8227SGreg Roach	/**
2098c2e8227SGreg Roach	 * Get all facts containing media links for this person and their spouse-family records
2108c2e8227SGreg Roach	 *
2118c2e8227SGreg Roach	 * @return Media[]
2128c2e8227SGreg Roach	 */
213764a01d9SGreg Roach	private function getMedia() {
2148c2e8227SGreg Roach		global $controller;
2158c2e8227SGreg Roach
2168c2e8227SGreg Roach		if ($this->media_list === null) {
2178c2e8227SGreg Roach			// Use facts from this individual and all their spouses
2188c2e8227SGreg Roach			$facts = $controller->record->getFacts();
2198c2e8227SGreg Roach			foreach ($controller->record->getSpouseFamilies() as $family) {
2208c2e8227SGreg Roach				foreach ($family->getFacts() as $fact) {
2218c2e8227SGreg Roach					$facts[] = $fact;
2228c2e8227SGreg Roach				}
2238c2e8227SGreg Roach			}
2248c2e8227SGreg Roach			// Use all media from each fact
22513abd6f3SGreg Roach			$this->media_list = [];
2268c2e8227SGreg Roach			foreach ($facts as $fact) {
2278c2e8227SGreg Roach				// Don't show pending edits, as the user just sees duplicates
2288c2e8227SGreg Roach				if (!$fact->isPendingDeletion()) {
2298c2e8227SGreg Roach					preg_match_all('/(?:^1|\n\d) OBJE @(' . WT_REGEX_XREF . ')@/', $fact->getGedcom(), $matches);
2308c2e8227SGreg Roach					foreach ($matches[1] as $match) {
23124ec66ceSGreg Roach						$media = Media::getInstance($match, $controller->record->getTree());
2328c2e8227SGreg Roach						if ($media && $media->canShow()) {
2338c2e8227SGreg Roach							$this->media_list[] = $media;
2348c2e8227SGreg Roach						}
2358c2e8227SGreg Roach					}
2368c2e8227SGreg Roach				}
2378c2e8227SGreg Roach			}
2388c2e8227SGreg Roach			// If a media object is linked twice, only show it once
2398c2e8227SGreg Roach			$this->media_list = array_unique($this->media_list);
2408c2e8227SGreg Roach			// Sort these using _WT_OBJE_SORT
24113abd6f3SGreg Roach			$wt_obje_sort = [];
2428c2e8227SGreg Roach			foreach ($controller->record->getFacts('_WT_OBJE_SORT') as $fact) {
2438c2e8227SGreg Roach				$wt_obje_sort[] = trim($fact->getValue(), '@');
2448c2e8227SGreg Roach			}
2458c2e8227SGreg Roach			usort($this->media_list, function (Media $x, Media $y) use ($wt_obje_sort) {
2468c2e8227SGreg Roach				return array_search($x->getXref(), $wt_obje_sort) - array_search($y->getXref(), $wt_obje_sort);
2478c2e8227SGreg Roach			});
2488c2e8227SGreg Roach		}
249cbc1590aSGreg Roach
2508c2e8227SGreg Roach		return $this->media_list;
2518c2e8227SGreg Roach	}
2528c2e8227SGreg Roach
25376692c8bSGreg Roach	/**
25476692c8bSGreg Roach	 * Can this tab load asynchronously?
25576692c8bSGreg Roach	 *
25676692c8bSGreg Roach	 * @return bool
25776692c8bSGreg Roach	 */
2588c2e8227SGreg Roach	public function canLoadAjax() {
259*15d603e7SGreg Roach		return false;
2608c2e8227SGreg Roach	}
2618c2e8227SGreg Roach
26276692c8bSGreg Roach	/**
26376692c8bSGreg Roach	 * Any content (e.g. Javascript) that needs to be rendered before the tabs.
26476692c8bSGreg Roach	 *
26576692c8bSGreg Roach	 * This function is probably not needed, as there are better ways to achieve this.
26676692c8bSGreg Roach	 *
26776692c8bSGreg Roach	 * @return string
26876692c8bSGreg Roach	 */
2698c2e8227SGreg Roach	public function getPreLoadContent() {
2708c2e8227SGreg Roach		return '';
2718c2e8227SGreg Roach	}
2728c2e8227SGreg Roach}
273