diff --git a/app/Helpers/MiscHelper.php b/app/Helpers/MiscHelper.php index aa04da7..bf224b4 100644 --- a/app/Helpers/MiscHelper.php +++ b/app/Helpers/MiscHelper.php @@ -43,6 +43,19 @@ class MiscHelper return sprintf('https://www.gravatar.com/avatar/%s?s=%d&d=%s', $hash, $size, $default); } + /** + * Tests whether the provided URL belongs to the current application (i.e. both scheme and hostname match.) + * @param $url + * @return bool + */ + public static function isSafeUrl($url) + { + $parts = parse_url($url); + $validParts = parse_url(url('/')); + + return ($parts['scheme'] == $validParts['scheme'] && $parts['host'] == $validParts['host']); + } + public static function randomString($length = 10) { $seed = 'abcdefghijklmnopqrstuvwxyz01234567890'; diff --git a/app/Http/Controllers/Gallery/AlbumController.php b/app/Http/Controllers/Gallery/AlbumController.php index 5069553..481af28 100644 --- a/app/Http/Controllers/Gallery/AlbumController.php +++ b/app/Http/Controllers/Gallery/AlbumController.php @@ -14,7 +14,7 @@ use Illuminate\Support\Facades\DB; class AlbumController extends Controller { - public function index($albumUrlAlias) + public function index(Request $request, $albumUrlAlias) { $album = DbHelper::loadAlbumByUrlAlias($albumUrlAlias); if (is_null($album)) @@ -23,14 +23,31 @@ class AlbumController extends Controller return null; } + $validViews = ['default', 'slideshow']; + $requestedView = strtolower($request->get('view')); + if (!in_array($requestedView, $validViews)) + { + $requestedView = $validViews[0]; + } + $this->authorizeForUser($this->getUser(), 'album.view', $album); + // The slideshow view needs access to all photos, not paged $photos = $album->photos() - ->orderBy(DB::raw('COALESCE(taken_at, created_at)')) - ->paginate(UserConfig::get('items_per_page')); + ->orderBy(DB::raw('COALESCE(taken_at, created_at)')); - return Theme::render('gallery.album', [ + if ($requestedView != 'slideshow') + { + $photos = $photos->paginate(UserConfig::get('items_per_page')); + } + else + { + $photos = $photos->get(); + } + + return Theme::render(sprintf('gallery.album_%s', $requestedView), [ 'album' => $album, + 'current_view' => $requestedView, 'photos' => $photos ]); } diff --git a/app/Http/Controllers/Gallery/PhotoController.php b/app/Http/Controllers/Gallery/PhotoController.php index e4dbb22..69a3636 100644 --- a/app/Http/Controllers/Gallery/PhotoController.php +++ b/app/Http/Controllers/Gallery/PhotoController.php @@ -6,6 +6,7 @@ use App\Album; use App\Facade\Theme; use App\Facade\UserConfig; use App\Helpers\DbHelper; +use App\Helpers\MiscHelper; use app\Http\Controllers\Admin\AlbumController; use App\Http\Controllers\Controller; use App\Http\Middleware\VerifyCsrfToken; @@ -58,7 +59,7 @@ class PhotoController extends Controller return response()->file($album->getAlbumSource()->getPathToPhoto($photo, $thumbnail)); } - public function show($albumUrlAlias, $photoFilename) + public function show(Request $request, $albumUrlAlias, $photoFilename) { $album = DbHelper::loadAlbumByUrlAlias($albumUrlAlias); if (is_null($album)) @@ -73,10 +74,18 @@ class PhotoController extends Controller $isOriginalAllowed = Gate::forUser($this->getUser())->allows('photo.download_original', $photo); + $returnAlbumUrl = $album->url(); + $referer = $request->headers->get('Referer'); + if (strlen($referer) > 0 && MiscHelper::isSafeUrl($referer)) + { + $returnAlbumUrl = $referer; + } + return Theme::render('gallery.photo', [ 'album' => $album, 'is_original_allowed' => $isOriginalAllowed, - 'photo' => $photo + 'photo' => $photo, + 'return_album_url' => $returnAlbumUrl ]); } diff --git a/public/themes/base/css/app.css b/public/themes/base/css/app.css index 0660324..e48de88 100644 --- a/public/themes/base/css/app.css +++ b/public/themes/base/css/app.css @@ -1,3 +1,16 @@ +.album-slideshow-container .image-preview { + height: 600px; + max-width: 100%; + width: 800px; +} + +.album-slideshow-container .thumbnails { + overflow-x: scroll; + overflow-y: hidden; + white-space: nowrap; + width: auto; +} + .no-margin-bottom { margin-bottom: 0; } diff --git a/public/themes/base/js/app.js b/public/themes/base/js/app.js index 217c5d5..6c70656 100644 --- a/public/themes/base/js/app.js +++ b/public/themes/base/js/app.js @@ -364,6 +364,67 @@ function EditPhotosViewModel(album_id, language, urls) { }; } +function SlideShowViewModel(required_timeout_ms) { + var self = this; + + self.current = ko.observable(); + self.currentIndex = ko.observable(0); + self.images = ko.observableArray(); + self.interval = null; + + self.isRunning = ko.observable(false); + self.isPaused = ko.observable(false); + + self.changeCurrentImage = function(photo_id) + { + for (var i = 0; i < self.images().length; i++) + { + var this_image = self.images()[i]; + if (this_image.id == photo_id) + { + self.current(this_image); + self.currentIndex(i); + window.clearInterval(self.interval); + self.interval = window.setInterval(self.rotateNextImage, required_timeout_ms); + return; + } + } + }; + + self.continueSlideshow = function() { + self.isPaused(false); + self.interval = window.setInterval(self.rotateNextImage, required_timeout_ms); + }; + + self.pauseSlideshow = function() { + self.isPaused(true); + window.clearInterval(self.interval); + }; + + self.rotateNextImage = function() { + var next_index = self.currentIndex() + 1; + if (next_index >= self.images().length) + { + next_index = 0; + } + + self.current(self.images()[next_index]); + self.currentIndex(next_index); + }; + + self.startSlideshow = function() { + if (self.images().length <= 0) + { + return; + } + + self.interval = window.setInterval(self.rotateNextImage, required_timeout_ms); + + self.current(self.images()[0]); + self.isRunning(true); + }; +} + function StorageLocationsViewModel() { var self = this; diff --git a/resources/lang/en/forms.php b/resources/lang/en/forms.php index 19b18b0..52ef5f5 100644 --- a/resources/lang/en/forms.php +++ b/resources/lang/en/forms.php @@ -3,6 +3,7 @@ return [ 'activate_user_label' => 'Manually activate this account', 'admin_user_label' => 'User is an administrator', 'album_source_label' => 'Storage location:', + 'album_view_label' => 'View as:', 'apply_action' => 'Apply', 'bulk_edit_photos_label' => 'Bulk edit selected photos:', 'bulk_edit_photos_placeholder' => 'Select an action', diff --git a/resources/lang/en/gallery.php b/resources/lang/en/gallery.php index 18a8a6e..975089d 100644 --- a/resources/lang/en/gallery.php +++ b/resources/lang/en/gallery.php @@ -1,5 +1,10 @@ [ + 'default' => 'Default', + 'slideshow' => 'Slideshow' + ], + 'back_to_album' => 'Back to :name', 'index_no_results_heading' => 'This gallery is empty!', 'index_no_results_text' => 'If you are the owner of this gallery, you can create new albums and upload photos using the :admin_link.' ]; \ No newline at end of file diff --git a/resources/views/themes/base/gallery/album.blade.php b/resources/views/themes/base/gallery/album_default.blade.php similarity index 90% rename from resources/views/themes/base/gallery/album.blade.php rename to resources/views/themes/base/gallery/album_default.blade.php index 3f46ce2..7db37dd 100644 --- a/resources/views/themes/base/gallery/album.blade.php +++ b/resources/views/themes/base/gallery/album_default.blade.php @@ -16,6 +16,10 @@
{{ $album->description }}