xref: /webtrees/app/Module/AlbumModule.php (revision 3fa66c660869af2f4c92ef37e06997aa8a0f55e1)
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\Gedcom;
21use Fisharebest\Webtrees\I18N;
22use Fisharebest\Webtrees\Individual;
23use Fisharebest\Webtrees\Media;
24
25/**
26 * Class AlbumModule
27 */
28class AlbumModule extends AbstractModule implements ModuleTabInterface
29{
30    /** @var Media[] List of media objects. */
31    private $media_list;
32
33    /**
34     * How should this module be labelled on tabs, menus, etc.?
35     *
36     * @return string
37     */
38    public function getTitle(): string
39    {
40        /* I18N: Name of a module */
41        return I18N::translate('Album');
42    }
43
44    /**
45     * A sentence describing what this module does.
46     *
47     * @return string
48     */
49    public function getDescription(): string
50    {
51        /* I18N: Description of the “Album” module */
52        return I18N::translate('An alternative to the “media” tab, and an enhanced image viewer.');
53    }
54
55    /**
56     * The user can re-arrange the tab order, but until they do, this
57     * is the order in which tabs are shown.
58     *
59     * @return int
60     */
61    public function defaultTabOrder(): int
62    {
63        return 60;
64    }
65
66    /**
67     * Is this tab empty? If so, we don't always need to display it.
68     *
69     * @param Individual $individual
70     *
71     * @return bool
72     */
73    public function hasTabContent(Individual $individual): bool
74    {
75        return $individual->canEdit() || $this->getMedia($individual);
76    }
77
78    /**
79     * A greyed out tab has no actual content, but may perhaps have
80     * options to create content.
81     *
82     * @param Individual $individual
83     *
84     * @return bool
85     */
86    public function isGrayedOut(Individual $individual): bool
87    {
88        return !$this->getMedia($individual);
89    }
90
91    /**
92     * Generate the HTML content of this tab.
93     *
94     * @param Individual $individual
95     *
96     * @return string
97     */
98    public function getTabContent(Individual $individual): string
99    {
100        return view('modules/lightbox/tab', [
101            'media_list' => $this->getMedia($individual),
102        ]);
103    }
104
105    /**
106     * Get all facts containing media links for this person and their spouse-family records
107     *
108     * @param Individual $individual
109     *
110     * @return Media[]
111     */
112    private function getMedia(Individual $individual): array
113    {
114        if ($this->media_list === null) {
115            // Use facts from this individual and all their spouses
116            $facts = $individual->facts();
117            foreach ($individual->getSpouseFamilies() as $family) {
118                foreach ($family->facts() as $fact) {
119                    $facts[] = $fact;
120                }
121            }
122            // Use all media from each fact
123            $this->media_list = [];
124            foreach ($facts as $fact) {
125                // Don't show pending edits, as the user just sees duplicates
126                if (!$fact->isPendingDeletion()) {
127                    preg_match_all('/(?:^1|\n\d) OBJE @(' . Gedcom::REGEX_XREF . ')@/', $fact->gedcom(), $matches);
128                    foreach ($matches[1] as $match) {
129                        $media = Media::getInstance($match, $individual->tree());
130                        if ($media && $media->canShow()) {
131                            $this->media_list[] = $media;
132                        }
133                    }
134                }
135            }
136            // If a media object is linked twice, only show it once
137            $this->media_list = array_unique($this->media_list);
138            // Sort these using _WT_OBJE_SORT
139            $wt_obje_sort = [];
140            foreach ($individual->facts(['_WT_OBJE_SORT']) as $fact) {
141                $wt_obje_sort[] = trim($fact->value(), '@');
142            }
143            usort($this->media_list, function (Media $x, Media $y) use ($wt_obje_sort): int {
144                return array_search($x->xref(), $wt_obje_sort) - array_search($y->xref(), $wt_obje_sort);
145            });
146        }
147
148        return $this->media_list;
149    }
150
151    /**
152     * Can this tab load asynchronously?
153     *
154     * @return bool
155     */
156    public function canLoadAjax(): bool
157    {
158        return false;
159    }
160}
161