1<?php 2/** 3 * webtrees: online genealogy 4 * Copyright (C) 2017 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\Auth; 19use Fisharebest\Webtrees\Database; 20use Fisharebest\Webtrees\Filter; 21use Fisharebest\Webtrees\Functions\FunctionsEdit; 22use Fisharebest\Webtrees\Functions\FunctionsPrint; 23use Fisharebest\Webtrees\GedcomTag; 24use Fisharebest\Webtrees\I18N; 25use Fisharebest\Webtrees\Media; 26use Fisharebest\Webtrees\Theme; 27 28/** 29 * Class SlideShowModule 30 */ 31class SlideShowModule extends AbstractModule implements ModuleBlockInterface { 32 /** {@inheritdoc} */ 33 public function getTitle() { 34 return /* I18N: Name of a module */ I18N::translate('Slide show'); 35 } 36 37 /** {@inheritdoc} */ 38 public function getDescription() { 39 return /* I18N: Description of the “Slide show” module */ I18N::translate('Random images from the current family tree.'); 40 } 41 42 /** 43 * Generate the HTML content of this block. 44 * 45 * @param int $block_id 46 * @param bool $template 47 * @param string[] $cfg 48 * 49 * @return string 50 */ 51 public function getBlock($block_id, $template = true, $cfg = []) { 52 global $ctype, $WT_TREE; 53 54 $filter = $this->getBlockSetting($block_id, 'filter', 'all'); 55 $controls = $this->getBlockSetting($block_id, 'controls', '1'); 56 $start = $this->getBlockSetting($block_id, 'start', '0') || Filter::getBool('start'); 57 58 // We can apply the filters using SQL 59 // Do not use "ORDER BY RAND()" - it is very slow on large tables. Use PHP::array_rand() instead. 60 $all_media = Database::prepare( 61 "SELECT m_id FROM `##media`" . 62 " WHERE m_file = ?" . 63 " AND m_ext IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '')" . 64 " AND m_type IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, '')" 65 )->execute([ 66 $WT_TREE->getTreeId(), 67 $this->getBlockSetting($block_id, 'filter_avi', '0') ? 'avi' : null, 68 $this->getBlockSetting($block_id, 'filter_bmp', '1') ? 'bmp' : null, 69 $this->getBlockSetting($block_id, 'filter_gif', '1') ? 'gif' : null, 70 $this->getBlockSetting($block_id, 'filter_jpeg', '1') ? 'jpg' : null, 71 $this->getBlockSetting($block_id, 'filter_jpeg', '1') ? 'jpeg' : null, 72 $this->getBlockSetting($block_id, 'filter_mp3', '0') ? 'mp3' : null, 73 $this->getBlockSetting($block_id, 'filter_ole', '1') ? 'ole' : null, 74 $this->getBlockSetting($block_id, 'filter_pcx', '1') ? 'pcx' : null, 75 $this->getBlockSetting($block_id, 'filter_pdf', '0') ? 'pdf' : null, 76 $this->getBlockSetting($block_id, 'filter_png', '1') ? 'png' : null, 77 $this->getBlockSetting($block_id, 'filter_tiff', '1') ? 'tiff' : null, 78 $this->getBlockSetting($block_id, 'filter_wav', '0') ? 'wav' : null, 79 $this->getBlockSetting($block_id, 'filter_audio', '0') ? 'audio' : null, 80 $this->getBlockSetting($block_id, 'filter_book', '1') ? 'book' : null, 81 $this->getBlockSetting($block_id, 'filter_card', '1') ? 'card' : null, 82 $this->getBlockSetting($block_id, 'filter_certificate', '1') ? 'certificate' : null, 83 $this->getBlockSetting($block_id, 'filter_coat', '1') ? 'coat' : null, 84 $this->getBlockSetting($block_id, 'filter_document', '1') ? 'document' : null, 85 $this->getBlockSetting($block_id, 'filter_electronic', '1') ? 'electronic' : null, 86 $this->getBlockSetting($block_id, 'filter_fiche', '1') ? 'fiche' : null, 87 $this->getBlockSetting($block_id, 'filter_film', '1') ? 'film' : null, 88 $this->getBlockSetting($block_id, 'filter_magazine', '1') ? 'magazine' : null, 89 $this->getBlockSetting($block_id, 'filter_manuscript', '1') ? 'manuscript' : null, 90 $this->getBlockSetting($block_id, 'filter_map', '1') ? 'map' : null, 91 $this->getBlockSetting($block_id, 'filter_newspaper', '1') ? 'newspaper' : null, 92 $this->getBlockSetting($block_id, 'filter_other', '1') ? 'other' : null, 93 $this->getBlockSetting($block_id, 'filter_painting', '1') ? 'painting' : null, 94 $this->getBlockSetting($block_id, 'filter_photo', '1') ? 'photo' : null, 95 $this->getBlockSetting($block_id, 'filter_tombstone', '1') ? 'tombstone' : null, 96 $this->getBlockSetting($block_id, 'filter_video', '0') ? 'video' : null, 97 ])->fetchOneColumn(); 98 99 // Keep looking through the media until a suitable one is found. 100 $random_media = null; 101 while ($all_media) { 102 $n = array_rand($all_media); 103 $media = Media::getInstance($all_media[$n], $WT_TREE); 104 if ($media->canShow() && !$media->isExternal()) { 105 // Check if it is linked to a suitable individual 106 foreach ($media->linkedIndividuals('OBJE') as $indi) { 107 if ( 108 $filter === 'all' || 109 $filter === 'indi' && strpos($indi->getGedcom(), "\n1 OBJE @" . $media->getXref() . '@') !== false || 110 $filter === 'event' && strpos($indi->getGedcom(), "\n2 OBJE @" . $media->getXref() . '@') !== false 111 ) { 112 // Found one :-) 113 $random_media = $media; 114 break 2; 115 } 116 } 117 } 118 unset($all_media[$n]); 119 } 120 121 $id = $this->getName() . $block_id; 122 $class = $this->getName() . '_block'; 123 if ($ctype === 'gedcom' && Auth::isManager($WT_TREE) || $ctype === 'user' && Auth::check()) { 124 $title = '<a class="icon-admin" title="' . I18N::translate('Preferences') . '" href="block_edit.php?block_id=' . $block_id . '&ged=' . $WT_TREE->getNameHtml() . '&ctype=' . $ctype . '"></a>'; 125 } else { 126 $title = ''; 127 } 128 $title .= $this->getTitle(); 129 130 if ($random_media) { 131 $content = "<div id=\"random_picture_container$block_id\">"; 132 if ($controls) { 133 if ($start) { 134 $icon_class = 'icon-media-stop'; 135 } else { 136 $icon_class = 'icon-media-play'; 137 } 138 $content .= '<div dir="ltr" class="center" id="random_picture_controls' . $block_id . '"><br>'; 139 $content .= '<a href="#" onclick="togglePlay(); return false;" id="play_stop" class="' . $icon_class . '" title="' . I18N::translate('Play') . '/' . I18N::translate('Stop') . '"></a>'; 140 $content .= '<a href="#" onclick="jQuery(\'#block_' . $block_id . '\').load(\'index.php?ctype=' . $ctype . '&action=ajax&block_id=' . $block_id . '\');return false;" title="' . I18N::translate('Next image') . '" class="icon-media-next"></a>'; 141 $content .= '</div><script> 142 var play = false; 143 function togglePlay() { 144 if (play) { 145 play = false; 146 jQuery("#play_stop").removeClass("icon-media-stop").addClass("icon-media-play"); 147 } 148 else { 149 play = true; 150 playSlideShow(); 151 jQuery("#play_stop").removeClass("icon-media-play").addClass("icon-media-stop"); 152 } 153 } 154 155 function playSlideShow() { 156 if (play) { 157 window.setTimeout("reload_image()", 6000); 158 } 159 } 160 function reload_image() { 161 if (play) { 162 jQuery("#block_' . $block_id . '").load("index.php?ctype=' . $ctype . '&action=ajax&block_id=' . $block_id . '&start=1"); 163 } 164 } 165 </script>'; 166 } 167 if ($start) { 168 $content .= '<script>togglePlay();</script>'; 169 } 170 $content .= '<div class="center" id="random_picture_content' . $block_id . '">'; 171 $content .= '<table id="random_picture_box"><tr><td class="details1">'; 172 $content .= $random_media->displayImage(); 173 174 $content .= '<br>'; 175 $content .= '<a href="' . $random_media->getHtmlUrl() . '"><b>' . $random_media->getFullName() . '</b></a><br>'; 176 foreach ($random_media->linkedIndividuals('OBJE') as $individual) { 177 $content .= '<a href="' . $individual->getHtmlUrl() . '">' . I18N::translate('View this individual') . ' — ' . $individual->getFullName() . '</a><br>'; 178 } 179 foreach ($random_media->linkedFamilies('OBJE') as $family) { 180 $content .= '<a href="' . $family->getHtmlUrl() . '">' . I18N::translate('View this family') . ' — ' . $family->getFullName() . '</a><br>'; 181 } 182 foreach ($random_media->linkedSources('OBJE') as $source) { 183 $content .= '<a href="' . $source->getHtmlUrl() . '">' . I18N::translate('View this source') . ' — ' . $source->getFullName() . '</a><br>'; 184 } 185 $content .= '<br><div class="indent">'; 186 $content .= FunctionsPrint::printFactNotes($random_media->getGedcom(), '1', false); 187 $content .= '</div>'; 188 $content .= '</td></tr></table>'; 189 $content .= '</div>'; // random_picture_content 190 $content .= '</div>'; // random_picture_container 191 } else { 192 $content = I18N::translate('This family tree has no images to display.'); 193 } 194 if ($template) { 195 return Theme::theme()->formatBlock($id, $title, $class, $content); 196 } else { 197 return $content; 198 } 199 } 200 201 /** {@inheritdoc} */ 202 public function loadAjax() { 203 return true; 204 } 205 206 /** {@inheritdoc} */ 207 public function isUserBlock() { 208 return true; 209 } 210 211 /** {@inheritdoc} */ 212 public function isGedcomBlock() { 213 return true; 214 } 215 216 /** 217 * An HTML form to edit block settings 218 * 219 * @param int $block_id 220 */ 221 public function configureBlock($block_id) { 222 if (Filter::postBool('save') && Filter::checkCsrf()) { 223 $this->setBlockSetting($block_id, 'filter', Filter::post('filter', 'indi|event|all', 'all')); 224 $this->setBlockSetting($block_id, 'controls', Filter::postBool('controls')); 225 $this->setBlockSetting($block_id, 'start', Filter::postBool('start')); 226 $this->setBlockSetting($block_id, 'filter_avi', Filter::postBool('filter_avi')); 227 $this->setBlockSetting($block_id, 'filter_bmp', Filter::postBool('filter_bmp')); 228 $this->setBlockSetting($block_id, 'filter_gif', Filter::postBool('filter_gif')); 229 $this->setBlockSetting($block_id, 'filter_jpeg', Filter::postBool('filter_jpeg')); 230 $this->setBlockSetting($block_id, 'filter_mp3', Filter::postBool('filter_mp3')); 231 $this->setBlockSetting($block_id, 'filter_ole', Filter::postBool('filter_ole')); 232 $this->setBlockSetting($block_id, 'filter_pcx', Filter::postBool('filter_pcx')); 233 $this->setBlockSetting($block_id, 'filter_pdf', Filter::postBool('filter_pdf')); 234 $this->setBlockSetting($block_id, 'filter_png', Filter::postBool('filter_png')); 235 $this->setBlockSetting($block_id, 'filter_tiff', Filter::postBool('filter_tiff')); 236 $this->setBlockSetting($block_id, 'filter_wav', Filter::postBool('filter_wav')); 237 $this->setBlockSetting($block_id, 'filter_audio', Filter::postBool('filter_audio')); 238 $this->setBlockSetting($block_id, 'filter_book', Filter::postBool('filter_book')); 239 $this->setBlockSetting($block_id, 'filter_card', Filter::postBool('filter_card')); 240 $this->setBlockSetting($block_id, 'filter_certificate', Filter::postBool('filter_certificate')); 241 $this->setBlockSetting($block_id, 'filter_coat', Filter::postBool('filter_coat')); 242 $this->setBlockSetting($block_id, 'filter_document', Filter::postBool('filter_document')); 243 $this->setBlockSetting($block_id, 'filter_electronic', Filter::postBool('filter_electronic')); 244 $this->setBlockSetting($block_id, 'filter_fiche', Filter::postBool('filter_fiche')); 245 $this->setBlockSetting($block_id, 'filter_film', Filter::postBool('filter_film')); 246 $this->setBlockSetting($block_id, 'filter_magazine', Filter::postBool('filter_magazine')); 247 $this->setBlockSetting($block_id, 'filter_manuscript', Filter::postBool('filter_manuscript')); 248 $this->setBlockSetting($block_id, 'filter_map', Filter::postBool('filter_map')); 249 $this->setBlockSetting($block_id, 'filter_newspaper', Filter::postBool('filter_newspaper')); 250 $this->setBlockSetting($block_id, 'filter_other', Filter::postBool('filter_other')); 251 $this->setBlockSetting($block_id, 'filter_painting', Filter::postBool('filter_painting')); 252 $this->setBlockSetting($block_id, 'filter_photo', Filter::postBool('filter_photo')); 253 $this->setBlockSetting($block_id, 'filter_tombstone', Filter::postBool('filter_tombstone')); 254 $this->setBlockSetting($block_id, 'filter_video', Filter::postBool('filter_video')); 255 } 256 257 $filter = $this->getBlockSetting($block_id, 'filter', 'all'); 258 $controls = $this->getBlockSetting($block_id, 'controls', '1'); 259 $start = $this->getBlockSetting($block_id, 'start', '0') || Filter::getBool('start'); 260 261 echo '<tr><td class="descriptionbox wrap width33">'; 262 echo /* I18N: Label for a configuration option */ I18N::translate('Show only individuals, events, or all'); 263 echo '</td><td class="optionbox">'; 264 echo FunctionsEdit::selectEditControl('filter', ['indi' => I18N::translate('Individuals'), 'event' => I18N::translate('Facts and events'), 'all' => I18N::translate('All')], null, $filter, ''); 265 echo '</td></tr>'; 266 267 $filters = [ 268 'avi' => $this->getBlockSetting($block_id, 'filter_avi', '0'), 269 'bmp' => $this->getBlockSetting($block_id, 'filter_bmp', '1'), 270 'gif' => $this->getBlockSetting($block_id, 'filter_gif', '1'), 271 'jpeg' => $this->getBlockSetting($block_id, 'filter_jpeg', '1'), 272 'mp3' => $this->getBlockSetting($block_id, 'filter_mp3', '0'), 273 'ole' => $this->getBlockSetting($block_id, 'filter_ole', '1'), 274 'pcx' => $this->getBlockSetting($block_id, 'filter_pcx', '1'), 275 'pdf' => $this->getBlockSetting($block_id, 'filter_pdf', '0'), 276 'png' => $this->getBlockSetting($block_id, 'filter_png', '1'), 277 'tiff' => $this->getBlockSetting($block_id, 'filter_tiff', '1'), 278 'wav' => $this->getBlockSetting($block_id, 'filter_wav', '0'), 279 'audio' => $this->getBlockSetting($block_id, 'filter_audio', '0'), 280 'book' => $this->getBlockSetting($block_id, 'filter_book', '1'), 281 'card' => $this->getBlockSetting($block_id, 'filter_card', '1'), 282 'certificate' => $this->getBlockSetting($block_id, 'filter_certificate', '1'), 283 'coat' => $this->getBlockSetting($block_id, 'filter_coat', '1'), 284 'document' => $this->getBlockSetting($block_id, 'filter_document', '1'), 285 'electronic' => $this->getBlockSetting($block_id, 'filter_electronic', '1'), 286 'fiche' => $this->getBlockSetting($block_id, 'filter_fiche', '1'), 287 'film' => $this->getBlockSetting($block_id, 'filter_film', '1'), 288 'magazine' => $this->getBlockSetting($block_id, 'filter_magazine', '1'), 289 'manuscript' => $this->getBlockSetting($block_id, 'filter_manuscript', '1'), 290 'map' => $this->getBlockSetting($block_id, 'filter_map', '1'), 291 'newspaper' => $this->getBlockSetting($block_id, 'filter_newspaper', '1'), 292 'other' => $this->getBlockSetting($block_id, 'filter_other', '1'), 293 'painting' => $this->getBlockSetting($block_id, 'filter_painting', '1'), 294 'photo' => $this->getBlockSetting($block_id, 'filter_photo', '1'), 295 'tombstone' => $this->getBlockSetting($block_id, 'filter_tombstone', '1'), 296 'video' => $this->getBlockSetting($block_id, 'filter_video', '0'), 297 ]; 298 299 ?> 300 <tr> 301 <td class="descriptionbox wrap width33"> 302 <?php echo I18N::translate('Filter'); ?> 303 </td> 304 <td class="optionbox"> 305 <center><b><?php echo GedcomTag::getLabel('FORM'); ?></b></center> 306 <table class="width100"> 307 <tr> 308 <td class="width33"> 309 <label> 310 <input type="checkbox" value="yes" name="filter_avi" <?php echo $filters['avi'] ? 'checked' : ''; ?>> 311 avi 312 </td> 313 <td class="width33"> 314 <label> 315 <input type="checkbox" value="yes" name="filter_bmp" <?php echo $filters['bmp'] ? 'checked' : ''; ?>> 316 bmp 317 </label> 318 </td> 319 <td class="width33"> 320 <label> 321 <input type="checkbox" value="yes" name="filter_gif" <?php echo $filters['gif'] ? 'checked' : ''; ?>> 322 gif 323 </label> 324 </td> 325 </tr> 326 <tr> 327 <td class="width33"> 328 <label> 329 <input type="checkbox" value="yes" name="filter_jpeg" <?php echo $filters['jpeg'] ? 'checked' : ''; ?>> 330 jpeg 331 </label> 332 </td> 333 <td class="width33"> 334 <label> 335 <input type="checkbox" value="yes" name="filter_mp3" <?php echo $filters['mp3'] ? 'checked' : ''; ?>> 336 mp3 337 </label> 338 </td> 339 <td class="width33"> 340 <label> 341 <input type="checkbox" value="yes" name="filter_ole" <?php echo $filters['ole'] ? 'checked' : ''; ?>> 342 ole 343 </label> 344 </td> 345 </tr> 346 <tr> 347 <td class="width33"> 348 <label> 349 <input type="checkbox" value="yes" name="filter_pcx" <?php echo $filters['pcx'] ? 'checked' : ''; ?>> 350 pcx 351 </label> 352 </td> 353 <td class="width33"> 354 <label> 355 <input type="checkbox" value="yes" name="filter_pdf" <?php echo $filters['pdf'] ? 'checked' : ''; ?>> 356 pdf 357 </label> 358 </td> 359 <td class="width33"> 360 <label> 361 <input type="checkbox" value="yes" name="filter_png" <?php echo $filters['png'] ? 'checked' : ''; ?>> 362 png 363 </label> 364 </td> 365 </tr> 366 <tr> 367 <td class="width33"> 368 <label> 369 <input type="checkbox" value="yes" name="filter_tiff" <?php echo $filters['tiff'] ? 'checked' : ''; ?>> 370 tiff 371 </label> 372 </td> 373 <td class="width33"> 374 <label> 375 <input type="checkbox" value="yes" name="filter_wav" <?php echo $filters['wav'] ? 'checked' : ''; ?>> 376 wav 377 </label> 378 </td> 379 <td class="width33"></td> 380 <td class="width33"></td> 381 </tr> 382 </table> 383 <br> 384 <center><b><?php echo GedcomTag::getLabel('TYPE'); ?></b></center> 385 <table class="width100"> 386 <tr> 387 <?php 388 //-- Build the list of checkboxes 389 $i = 0; 390 foreach (GedcomTag::getFileFormTypes() as $typeName => $typeValue) { 391 $i++; 392 if ($i > 3) { 393 $i = 1; 394 echo '</tr><tr>'; 395 } 396 echo '<td class="width33"><label><input type="checkbox" value="yes" name="filter_' . $typeName . '" '; 397 echo $filters[$typeName] ? 'checked' : ''; 398 echo '> ' . $typeValue . '</label></td>'; 399 } 400 ?> 401 </tr> 402 </table> 403 </td> 404 </tr> 405 406 <?php 407 408 echo '<tr><td class="descriptionbox wrap width33">'; 409 echo /* I18N: Label for a configuration option */ I18N::translate('Show slide show controls'); 410 echo '</td><td class="optionbox">'; 411 echo FunctionsEdit::editFieldYesNo('controls', $controls); 412 echo '</td></tr>'; 413 414 echo '<tr><td class="descriptionbox wrap width33">'; 415 echo /* I18N: Label for a configuration option */ I18N::translate('Start slide show on page load'); 416 echo '</td><td class="optionbox">'; 417 echo FunctionsEdit::editFieldYesNo('start', $start); 418 echo '</td></tr>'; 419 } 420} 421