More simple lightbox for SDK and compatible with custom History
Changes to go along with https://github.com/matrix-org/matrix-public-archive/pull/12 Split out from https://github.com/vector-im/hydrogen-web/pull/653
This commit is contained in:
parent
8b2299852e
commit
ad56f4db4f
7 changed files with 129 additions and 32 deletions
|
@ -28,12 +28,14 @@ import type {Clock} from "../platform/web/dom/Clock";
|
|||
import type {ILogger} from "../logging/types";
|
||||
import type {Navigation} from "./navigation/Navigation";
|
||||
import type {URLRouter} from "./navigation/URLRouter";
|
||||
import type {History} from "../platform/web/dom/History";
|
||||
|
||||
export type Options = {
|
||||
platform: Platform
|
||||
logger: ILogger
|
||||
urlCreator: URLRouter
|
||||
navigation: Navigation
|
||||
history: History
|
||||
emitChange?: (params: any) => void
|
||||
}
|
||||
|
||||
|
@ -142,4 +144,8 @@ export class ViewModel<O extends Options = Options> extends EventEmitter<{change
|
|||
get navigation(): Navigation {
|
||||
return this._options.navigation;
|
||||
}
|
||||
|
||||
get history(): History {
|
||||
return this._options.history;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import {RoomViewModel} from "./room/RoomViewModel.js";
|
|||
import {UnknownRoomViewModel} from "./room/UnknownRoomViewModel.js";
|
||||
import {InviteViewModel} from "./room/InviteViewModel.js";
|
||||
import {RoomBeingCreatedViewModel} from "./room/RoomBeingCreatedViewModel.js";
|
||||
import {LightboxViewModel} from "./room/LightboxViewModel.js";
|
||||
import {setupLightboxNavigation} from "./room/lightbox-navigation.js";
|
||||
import {SessionStatusViewModel} from "./SessionStatusViewModel.js";
|
||||
import {RoomGridViewModel} from "./RoomGridViewModel.js";
|
||||
import {SettingsViewModel} from "./settings/SettingsViewModel.js";
|
||||
|
@ -81,12 +81,12 @@ export class SessionViewModel extends ViewModel {
|
|||
}));
|
||||
this._updateCreateRoom(createRoom.get());
|
||||
|
||||
const lightbox = this.navigation.observe("lightbox");
|
||||
this.track(lightbox.subscribe(eventId => {
|
||||
this._updateLightbox(eventId);
|
||||
}));
|
||||
this._updateLightbox(lightbox.get());
|
||||
|
||||
setupLightboxNavigation(this, 'lightboxViewModel', (eventId) => {
|
||||
return {
|
||||
room,
|
||||
eventId,
|
||||
};
|
||||
});
|
||||
|
||||
const rightpanel = this.navigation.observe("right-panel");
|
||||
this.track(rightpanel.subscribe(() => this._updateRightPanel()));
|
||||
|
@ -267,21 +267,6 @@ export class SessionViewModel extends ViewModel {
|
|||
this.emitChange("activeMiddleViewModel");
|
||||
}
|
||||
|
||||
_updateLightbox(eventId) {
|
||||
if (this._lightboxViewModel) {
|
||||
this._lightboxViewModel = this.disposeTracked(this._lightboxViewModel);
|
||||
}
|
||||
if (eventId) {
|
||||
const room = this._roomFromNavigation();
|
||||
this._lightboxViewModel = this.track(new LightboxViewModel(this.childOptions({eventId, room})));
|
||||
}
|
||||
this.emitChange("lightboxViewModel");
|
||||
}
|
||||
|
||||
get lightboxViewModel() {
|
||||
return this._lightboxViewModel;
|
||||
}
|
||||
|
||||
_roomFromNavigation() {
|
||||
const roomId = this.navigation.path.get("room")?.value;
|
||||
const room = this._client.session.rooms.get(roomId);
|
||||
|
|
|
@ -19,21 +19,25 @@ 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 = null;
|
||||
this._date = null;
|
||||
this._subscribeToEvent(options.room, options.eventId);
|
||||
}
|
||||
|
||||
_subscribeToEvent(room, eventId) {
|
||||
const eventObservable = room.observeEvent(eventId);
|
||||
this.track(eventObservable.subscribe(eventEntry => {
|
||||
this._loadEvent(room, eventEntry);
|
||||
}));
|
||||
this._loadEvent(room, eventObservable.get());
|
||||
let event = this._eventEntry;
|
||||
if (!this._eventEntry) {
|
||||
const eventObservable = room.observeEvent(eventId);
|
||||
this.track(eventObservable.subscribe(eventEntry => {
|
||||
this._loadEvent(room, eventEntry);
|
||||
}));
|
||||
event = eventObservable.get();
|
||||
}
|
||||
this._loadEvent(room, event);
|
||||
}
|
||||
|
||||
async _loadEvent(room, eventEntry) {
|
||||
|
@ -92,6 +96,6 @@ export class LightboxViewModel extends ViewModel {
|
|||
}
|
||||
|
||||
close() {
|
||||
this.platform.history.pushUrl(this.closeUrl);
|
||||
this.history.pushUrl(this.closeUrl);
|
||||
}
|
||||
}
|
||||
|
|
69
src/domain/session/room/lightbox-navigation.js
Normal file
69
src/domain/session/room/lightbox-navigation.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
Copyright 2022 Bruno Windels <bruno@windels.cloud>
|
||||
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');
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
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, lightboxChildOptionsFunction(eventId));
|
||||
}));
|
||||
// Also handle the case where the URL already includes `/lightbox/$eventId` (like
|
||||
// from page-load)
|
||||
const initialLightBoxEventId = lightbox.get();
|
||||
updateLightboxViewModel(vm, fieldName, lightboxChildOptionsFunction(initialLightBoxEventId));
|
||||
}
|
|
@ -25,6 +25,8 @@ export {SessionViewModel} from "./domain/session/SessionViewModel.js";
|
|||
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} from "./domain/session/room/lightbox-navigation.js";
|
||||
export {TimelineViewModel} from "./domain/session/room/timeline/TimelineViewModel.js";
|
||||
export {tileClassForEntry} from "./domain/session/room/timeline/tiles/index";
|
||||
export type {TimelineEntry, TileClassForEntryFn, Options, TileConstructor} from "./domain/session/room/timeline/tiles/index";
|
||||
|
@ -62,6 +64,7 @@ export {TextMessageView} from "./platform/web/ui/session/room/timeline/TextMessa
|
|||
export {VideoView} from "./platform/web/ui/session/room/timeline/VideoView.js";
|
||||
|
||||
export {Navigation} from "./domain/navigation/Navigation.js";
|
||||
export {History} from "./platform/web/dom/History.js";
|
||||
export {ComposerViewModel} from "./domain/session/room/ComposerViewModel.js";
|
||||
export {MessageComposer} from "./platform/web/ui/session/room/MessageComposer.js";
|
||||
export {TemplateView} from "./platform/web/ui/general/TemplateView";
|
||||
|
|
|
@ -30,10 +30,10 @@ export class History extends BaseObservableValue {
|
|||
But for SSO, we need to handle <root>/?loginToken=<TOKEN>
|
||||
Handle that as a special case for now.
|
||||
*/
|
||||
if (document.location.search.includes("loginToken")) {
|
||||
if (document?.location?.search.includes("loginToken")) {
|
||||
return document.location.search;
|
||||
}
|
||||
return document.location.hash;
|
||||
return document?.location?.hash;
|
||||
}
|
||||
|
||||
/** does not emit */
|
||||
|
|
30
src/platform/web/ui/general/Link.js
Normal file
30
src/platform/web/ui/general/Link.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Copyright 2020 Bruno Windels <bruno@windels.cloud>
|
||||
|
||||
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 {TemplateView} from "./general/TemplateView";
|
||||
|
||||
export class LinkView extends TemplateView {
|
||||
render(t, vm) {
|
||||
return t.a({
|
||||
...vm,
|
||||
onClick: (e) => {
|
||||
// Allow the `urlRouter` to cancel the URL navigation and any upstream
|
||||
// consumer that added their own `onClick` handler.
|
||||
return vm.urlCreator.linkClick(this, e) || vm.onClick?.(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
Reference in a new issue