diff --git a/src/domain/session/SessionViewModel.js b/src/domain/session/SessionViewModel.js index b3a63c9d..3b0c63d1 100644 --- a/src/domain/session/SessionViewModel.js +++ b/src/domain/session/SessionViewModel.js @@ -81,7 +81,12 @@ export class SessionViewModel extends ViewModel { })); this._updateCreateRoom(createRoom.get()); - setupLightboxNavigation(this, 'lightboxViewModel'); + setupLightboxNavigation(this, 'lightboxViewModel', (eventId) => { + return { + room, + eventId, + }; + }); const rightpanel = this.navigation.observe("right-panel"); this.track(rightpanel.subscribe(() => this._updateRightPanel())); diff --git a/src/domain/session/room/LightboxViewModel.js b/src/domain/session/room/LightboxViewModel.js index 527dfa5d..52e518c7 100644 --- a/src/domain/session/room/LightboxViewModel.js +++ b/src/domain/session/room/LightboxViewModel.js @@ -19,11 +19,11 @@ import {ViewModel} from "../../ViewModel"; export class LightboxViewModel extends ViewModel { constructor(options) { super(options); - this._eventId = options.eventId; + this._eventEntry = options.eventEntry; + this._eventId = options.eventId || options.eventEntry.id; this._unencryptedImageUrl = null; this._decryptedImage = null; this._closeUrl = this.urlCreator.urlUntilSegment("room"); - this._eventEntry = options.eventEntry; this._date = null; this._subscribeToEvent(options.room, options.eventId); } diff --git a/src/domain/session/room/lightbox-navigation.js b/src/domain/session/room/lightbox-navigation.js index c56a04f4..1cc2886c 100644 --- a/src/domain/session/room/lightbox-navigation.js +++ b/src/domain/session/room/lightbox-navigation.js @@ -1,31 +1,69 @@ +/* +Copyright 2022 Bruno Windels +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + import {LightboxViewModel} from "./LightboxViewModel.js"; +// Store the `LightboxViewModel` under a symbol so no one else can tamper with +// it. This acts like a private field on the class since no one else has the +// symbol to look it up. let lightboxViewModelSymbol = Symbol('lightboxViewModel'); -export function updateLightboxViewModel(vm, fieldName, eventId) { +/** + * Destroys and creates a new the `LightboxViewModel` depending if + * `lightboxChildOptions.eventEntry` or `lightboxChildOptions.eventId` are + * provided. + */ +function updateLightboxViewModel(vm, fieldName, lightboxChildOptions) { + // Remove any existing `LightboxViewModel` before we assemble the new one below if (vm[lightboxViewModelSymbol]) { vm[lightboxViewModelSymbol] = vm.disposeTracked(vm[lightboxViewModelSymbol]); + // Let the `LightboxView` know that the `LightboxViewModel` has changed vm.emitChange(fieldName); } - if (eventId) { - const room = vm._roomFromNavigation(); - vm[lightboxViewModelSymbol] = vm.track(new LightboxViewModel(vm.childOptions({eventId, room}))); + // Create the new `LightboxViewModel` if the `eventEntry` exists directly or + // `eventId` which we can load from the store + if (lightboxChildOptions.eventId || lightboxChildOptions.eventEntry) { + vm[lightboxViewModelSymbol] = vm.track(new LightboxViewModel(vm.childOptions(lightboxChildOptions))); + // Let the `LightboxView` know that the `LightboxViewModel` has changed vm.emitChange(fieldName); } } -// Whenever the page navigates somewhere, keep the lightboxViewModel up to date -export function setupLightboxNavigation(vm, fieldName = 'lightboxViewModel') { +/** + * Handles updating the `LightboxViewModel` whenever the page URL changes and + * emits changes which the `LightboxView` will use to re-render. This is a + * composable piece of logic to call in an existing `ViewModel`'s constructor. + */ +export function setupLightboxNavigation(vm, fieldName = 'lightboxViewModel', lightboxChildOptionsFunction) { + // On the given `vm`, create a getter at `fieldName` that the + // `LightboxViewModel` is exposed at for usage in the view. Object.defineProperty(vm, fieldName, { get: function() { - vm[lightboxViewModelSymbol]; + return vm[lightboxViewModelSymbol]; } }); + // Whenever the page navigates somewhere, keep the `lightboxViewModel` up to date const lightbox = vm.navigation.observe("lightbox"); vm.track(lightbox.subscribe(eventId => { - updateLightboxViewModel(vm, fieldName, eventId); + updateLightboxViewModel(vm, fieldName, lightboxChildOptionsFunction(eventId)); })); + // Also handle the case where the URL already includes `/lightbox/$eventId` (like + // from page-load) const initialLightBoxEventId = lightbox.get(); - updateLightboxViewModel(vm, fieldName, initialLightBoxEventId); + updateLightboxViewModel(vm, fieldName, lightboxChildOptionsFunction(initialLightBoxEventId)); } diff --git a/src/lib.ts b/src/lib.ts index c15a8981..9d0ca367 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -26,7 +26,7 @@ export {SessionView} from "./platform/web/ui/session/SessionView.js"; export {RoomViewModel} from "./domain/session/room/RoomViewModel.js"; export {RoomView} from "./platform/web/ui/session/room/RoomView.js"; export {LightboxView} from "./platform/web/ui/session/room/LightboxView.js"; -export {setupLightboxNavigation, updateLightboxViewModel} from "./domain/session/room/lightbox-navigation.js"; +export {setupLightboxNavigation} from "./domain/session/room/lightbox-navigation.js"; export {RightPanelView} from "./platform/web/ui/session/rightpanel/RightPanelView.js"; export {MediaRepository} from "./matrix/net/MediaRepository"; export {TilesCollection} from "./domain/session/room/timeline/TilesCollection.js";