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