From b582360e6e0931485670ec20d2d49b99ac068eca Mon Sep 17 00:00:00 2001 From: Kamil Iskra Date: Fri, 19 Aug 2022 14:18:18 -0500 Subject: [PATCH] Support the back button in search results (#306) * Also don't auto-play videos loaded after a delete --- scripts/main/album.js | 14 +++++-- scripts/main/contextMenu.js | 2 +- scripts/main/header.js | 2 +- scripts/main/lychee.js | 83 ++++++++++++++++++++++++------------- scripts/main/photo.js | 4 +- scripts/main/search.js | 10 +++-- scripts/main/sidebar.js | 2 +- scripts/main/visible.js | 2 +- 8 files changed, 78 insertions(+), 41 deletions(-) diff --git a/scripts/main/album.js b/scripts/main/album.js index 3ab15eed..803948c8 100644 --- a/scripts/main/album.js +++ b/scripts/main/album.js @@ -20,7 +20,7 @@ album.isSmartID = function (id) { * @returns {boolean} */ album.isSearchID = function (id) { - return id === SearchAlbumID; + return id === SearchAlbumIDPrefix || id.startsWith(SearchAlbumIDPrefix + "/"); }; /** @@ -50,7 +50,7 @@ album.getID = function () { // this is a Lambda let isID = (_id) => { - return album.isSmartID(_id) || /*album.isSearchID(_id) || */ album.isModelID(_id); + return album.isSmartID(_id) || album.isSearchID(_id) || album.isModelID(_id); }; if (photo.json) id = photo.json.album_id; @@ -176,16 +176,24 @@ album.deleteSubByID = function (albumID) { /** * @param {string} albumID * @param {?AlbumLoadedCB} [albumLoadedCB=null] + * @param {?string} parentID * * @returns {void} */ -album.load = function (albumID, albumLoadedCB = null) { +album.load = function (albumID, albumLoadedCB = null, parentID = null) { /** * @param {Album} data */ const processAlbum = function (data) { album.json = data; + if (parentID !== null) { + // Used with search so that the back button sends back to the + // search results. + album.json.original_parent_id = album.json.parent_id; + album.json.parent_id = parentID; + } + if (albumLoadedCB === null) { lychee.animate(lychee.content, "contentZoomOut"); } diff --git a/scripts/main/contextMenu.js b/scripts/main/contextMenu.js index 0836e136..098e5d0c 100644 --- a/scripts/main/contextMenu.js +++ b/scripts/main/contextMenu.js @@ -380,7 +380,7 @@ contextMenu.photo = function (photoID, e) { { title: build.iconic("trash") + lychee.locale["DELETE"], fn: () => photo.delete([photoID]) }, { title: build.iconic("cloud-download") + lychee.locale["DOWNLOAD"], fn: () => photo.getArchive([photoID]) }, ]; - if (album.isSmartID(album.getID()) || album.isSearchID(album.getID) || album.isTagAlbum()) { + if (album.isSmartID(album.getID()) || album.isSearchID(album.getID()) || album.isTagAlbum()) { // Cover setting not supported for smart or tag albums and search results. items.splice(2, 1); } diff --git a/scripts/main/header.js b/scripts/main/header.js index d2b53e8b..b10aabc0 100644 --- a/scripts/main/header.js +++ b/scripts/main/header.js @@ -138,7 +138,7 @@ header.bind = function () { header.dom(".header__search").on("keyup click", function () { if ($(this).val().length > 0) { - lychee.goto("search/" + encodeURIComponent($(this).val())); + lychee.goto(SearchAlbumIDPrefix + "/" + encodeURIComponent($(this).val())); } else if (search.json !== null) { search.reset(); } diff --git a/scripts/main/lychee.js b/scripts/main/lychee.js index f2dc23fd..b8b521b3 100644 --- a/scripts/main/lychee.js +++ b/scripts/main/lychee.js @@ -583,13 +583,31 @@ lychee.reloadIfLegacyIDs = function (albumID, photoID, autoplay) { }; /** + * This is a "God method" that is used to load pretty much anything, based + * on what's in the web browser's URL bar after the '#' character: + * + * (nothing) --> load root album, assign null to albumID and photoID + * {albumID} --> load the album; albumID equals the given ID, photoID is null + * {albumID}/{photoID} --> load album (if not already loaded) and then the + * corresponding photo, assign the respective values to albumID and photoID + * map --> load the map of all albums + * map/{albumID} --> load the map of the respective album + * search/{term} --> load or go back to "search" album for the given term, + * assign 'search/{term}' as fictitious albumID and assign null to photoID + * search/{term}/{photoID} --> load photo within fictitious search album, + * assign 'search/{term}' as fictitious albumID and assign the given ID to + * photoID + * * @param {boolean} [autoplay=true] * @returns {void} */ lychee.load = function (autoplay = true) { let hash = document.location.hash.replace("#", "").split("/"); let albumID = hash[0]; - let photoID = hash[1]; + if (albumID === SearchAlbumIDPrefix && hash.length > 1) { + albumID += "/" + hash[1]; + } + let photoID = hash[album.isSearchID(albumID) ? 2 : 1]; contextMenu.close(); multiselect.close(); @@ -618,24 +636,6 @@ lychee.load = function (autoplay = true) { } mapview.open(albumID); lychee.footer_hide(); - } else if (albumID === "search") { - // Search has been triggered - const search_string = decodeURIComponent(photoID); - - if (search_string.trim() === "") { - // do nothing on "only space" search strings - return; - } - // If public search is disabled -> do nothing - if (lychee.publicMode === true && !lychee.public_search) { - loadingBar.show("error", lychee.locale["ERROR_SEARCH_DEACTIVATED"]); - return; - } - - header.dom(".header__search").val(search_string); - search.find(search_string); - - lychee.footer_show(); } else { if (lychee.reloadIfLegacyIDs(albumID, photoID, autoplay)) { return; @@ -673,12 +673,7 @@ lychee.load = function (autoplay = true) { // If we don't have an album or the wrong album load the album // first and let the album loader load the photo afterwards or // load the photo directly. - if ( - lychee.content.html() === "" || - album.json === null || - album.json.id !== albumID || - (header.dom(".header__search").length && header.dom(".header__search").val().length !== 0) - ) { + if (lychee.content.html() === "" || album.json === null || album.json.id !== albumID) { lychee.content.hide(); album.load(albumID, loadPhoto); } else { @@ -703,8 +698,6 @@ lychee.load = function (autoplay = true) { if (visible.sidebar()) sidebar.toggle(false); mapview.open(); lychee.footer_hide(); - } else if (albumID === "search") { - // search string is empty -> do nothing } else { if (lychee.reloadIfLegacyIDs(albumID, photoID, autoplay)) { return; @@ -723,12 +716,46 @@ lychee.load = function (autoplay = true) { if (visible.sidebar() && (album.isSmartID(albumID) || album.isSearchID(albumID))) sidebar.toggle(false); $("#sensitive_warning").hide(); if (album.json && albumID === album.json.id) { - view.album.title(); + if (album.isSearchID(albumID)) { + // We are probably coming back to the search results from + // viewing an image. Because search results is not a + // regular album, it needs to be treated a little + // differently. + header.setMode("albums"); + lychee.setTitle(lychee.locale["SEARCH_RESULTS"], false); + } else { + view.album.title(); + } lychee.content.show(); tabindex.makeFocusable(lychee.content, true); // If the album was loaded in the background (when content is // hidden), scrolling may not have worked. view.album.content.restoreScroll(); + } else if (album.isSearchID(albumID)) { + // Search has been triggered + let search_string = decodeURIComponent(hash[1]).trim(); + + if (search_string === "") { + // do nothing on "only space" search strings + return; + } + // If public search is disabled -> do nothing + if (lychee.publicMode === true && !lychee.public_search) { + loadingBar.show("error", lychee.locale["ERROR_SEARCH_DEACTIVATED"]); + return; + } + + header.dom(".header__search").val(search_string); + search.find(search_string); + } else if (visible.search()) { + // Somebody clicked on an album in search results. We + // will alter the parent_id of that album once it's loaded + // so that the back button sends us back to the search + // results. + // Trash data so that it's reloaded if needed (just as we + // would for a regular parent album). + search.json = null; + album.load(albumID, null, album.getID()); } else { album.load(albumID); } diff --git a/scripts/main/photo.js b/scripts/main/photo.js index a57ac60c..f66b3bdb 100644 --- a/scripts/main/photo.js +++ b/scripts/main/photo.js @@ -328,9 +328,9 @@ photo.delete = function (photoIDs) { // Show album otherwise. if (visible.photo()) { if (nextPhotoID !== null && nextPhotoID !== photo.getID()) { - lychee.goto(album.getID() + "/" + nextPhotoID); + lychee.goto(album.getID() + "/" + nextPhotoID, false); } else if (previousPhotoID !== null && previousPhotoID !== photo.getID()) { - lychee.goto(album.getID() + "/" + previousPhotoID); + lychee.goto(album.getID() + "/" + previousPhotoID, false); } else { lychee.goto(album.getID()); } diff --git a/scripts/main/search.js b/scripts/main/search.js index e07426bc..3de4a070 100644 --- a/scripts/main/search.js +++ b/scripts/main/search.js @@ -9,7 +9,7 @@ * * @type {string} */ -const SearchAlbumID = "search"; +const SearchAlbumIDPrefix = "search"; /** * @typedef SearchAlbum @@ -18,7 +18,7 @@ const SearchAlbumID = "search"; * mostly compatible with the other album types, i.e. * {@link Album}, {@link TagAlbum} and {@link SmartAlbum}. * - * @property {string} id - always equals `SearchAlbumID` + * @property {string} id - always equals `SearchAlbumIDPrefix/search-term` * @property {string} title - always equals `lychee.locale["SEARCH_RESULTS"]` * @property {Photo[]} photos - the found photos * @property {Album[]} albums - the found albums @@ -46,8 +46,10 @@ search.find = function (term) { /** @param {SearchResult} data */ const successHandler = function (data) { - // Do nothing, if search result is identical to previous result if (search.json && search.json.checksum === data.checksum) { + // If search result is identical to previous result, just + // update the album id with the new search term and bail out. + album.json.id = SearchAlbumIDPrefix + "/" + term; return; } @@ -55,7 +57,7 @@ search.find = function (term) { // Create and assign a `SearchAlbum` album.json = { - id: SearchAlbumID, + id: SearchAlbumIDPrefix + "/" + term, title: lychee.locale["SEARCH_RESULTS"], photos: search.json.photos, albums: search.json.albums, diff --git a/scripts/main/sidebar.js b/scripts/main/sidebar.js index cbc77972..fa4388ed 100644 --- a/scripts/main/sidebar.js +++ b/scripts/main/sidebar.js @@ -115,7 +115,7 @@ sidebar.triggerSearch = function (search_string) { search.json = null; // We're either logged in or public search is allowed - lychee.goto("search/" + encodeURIComponent(search_string)); + lychee.goto(SearchAlbumIDPrefix + "/" + encodeURIComponent(search_string)); }; /** diff --git a/scripts/main/visible.js b/scripts/main/visible.js index 25be652a..ecc372e5 100644 --- a/scripts/main/visible.js +++ b/scripts/main/visible.js @@ -34,7 +34,7 @@ visible.config = function () { /** @returns {boolean} */ visible.search = function () { - return search.json !== null; + return visible.albums() && album.json !== null && album.isSearchID(album.json.id); }; /** @returns {boolean} */