From fbf72b88251fa8ddd18ff17879d1169d28f99394 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 12 Aug 2020 17:38:40 +0200 Subject: [PATCH 1/4] bind key for spontaneous updates in MappedMap so we just have to pass in the params --- src/observable/map/MappedMap.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/observable/map/MappedMap.js b/src/observable/map/MappedMap.js index 96cec32e..51a23d41 100644 --- a/src/observable/map/MappedMap.js +++ b/src/observable/map/MappedMap.js @@ -16,7 +16,7 @@ limitations under the License. import {BaseObservableMap} from "./BaseObservableMap.js"; /* -so a mapped value can emit updates on it's own with this._updater that is passed in the mapping function +so a mapped value can emit updates on it's own with this._emitSpontaneousUpdate that is passed in the mapping function how should the mapped value be notified of an update though? and can it then decide to not propagate the update? */ export class MappedMap extends BaseObservableMap { @@ -25,14 +25,18 @@ export class MappedMap extends BaseObservableMap { this._source = source; this._mapper = mapper; this._mappedValues = new Map(); - this._updater = (key, params) => { // this should really be (value, params) but can't make that work for now - const value = this._mappedValues.get(key); - this.onUpdate(key, value, params); - }; + } + + _emitSpontaneousUpdate(key, params) { + const value = this._mappedValues.get(key); + if (value) { + this.emitUpdate(key, value, params); + } } onAdd(key, value) { - const mappedValue = this._mapper(value, this._updater); + const emitSpontaneousUpdate = this._emitSpontaneousUpdate.bind(this, key); + const mappedValue = this._mapper(value, emitSpontaneousUpdate); this._mappedValues.set(key, mappedValue); this.emitAdd(key, mappedValue); } @@ -47,17 +51,16 @@ export class MappedMap extends BaseObservableMap { onUpdate(key, value, params) { const mappedValue = this._mappedValues.get(key); if (mappedValue !== undefined) { - const newParams = this._updater(value, params); - // if (newParams !== undefined) { - this.emitUpdate(key, mappedValue, newParams); - // } + // TODO: map params somehow if needed? + this.emitUpdate(key, mappedValue, params); } } onSubscribeFirst() { this._subscription = this._source.subscribe(this); for (let [key, value] of this._source) { - const mappedValue = this._mapper(value, this._updater); + const emitSpontaneousUpdate = this._emitSpontaneousUpdate.bind(this, key); + const mappedValue = this._mapper(value, emitSpontaneousUpdate); this._mappedValues.set(key, mappedValue); } super.onSubscribeFirst(); From 7f50e3d137de237907cef0418130dde4d7fc62b5 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 12 Aug 2020 17:39:11 +0200 Subject: [PATCH 2/4] allow overriding the "emit change" mechanism in ViewModel so view models that should send updates through their collection can still use the same "emitChange" method on ViewModel --- src/domain/ViewModel.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/domain/ViewModel.js b/src/domain/ViewModel.js index 2f34e536..4f73702a 100644 --- a/src/domain/ViewModel.js +++ b/src/domain/ViewModel.js @@ -22,10 +22,10 @@ import {EventEmitter} from "../utils/EventEmitter.js"; import {Disposables} from "../utils/Disposables.js"; export class ViewModel extends EventEmitter { - constructor({clock} = {}) { + constructor({clock, emitChange} = {}) { super(); this.disposables = null; - this._options = {clock}; + this._options = {clock, emitChange}; } childOptions(explicitOptions) { @@ -71,7 +71,11 @@ export class ViewModel extends EventEmitter { } emitChange(changedProps) { - this.emit("change", changedProps); + if (this._options.emitChange) { + this._options.emitChange(changedProps); + } else { + this.emit("change", changedProps); + } } get clock() { From 5aacf85166d2fc7d9224140f5b50a7e9fad1e578 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 12 Aug 2020 17:40:41 +0200 Subject: [PATCH 3/4] mark room tile as active when clicked --- src/domain/session/SessionViewModel.js | 13 +++++++--- .../session/roomlist/RoomTileViewModel.js | 25 ++++++++++++++++--- src/ui/web/session/RoomTile.js | 2 +- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/domain/session/SessionViewModel.js b/src/domain/session/SessionViewModel.js index 3737ebac..879c5e26 100644 --- a/src/domain/session/SessionViewModel.js +++ b/src/domain/session/SessionViewModel.js @@ -28,12 +28,13 @@ export class SessionViewModel extends ViewModel { sync: sessionContainer.sync, reconnector: sessionContainer.reconnector }))); + this._currentRoomTileViewModel = null; this._currentRoomViewModel = null; - const roomTileVMs = this._session.rooms.mapValues((room, emitUpdate) => { + const roomTileVMs = this._session.rooms.mapValues((room, emitChange) => { return new RoomTileViewModel({ room, - emitUpdate, - emitOpen: room => this._openRoom(room) + emitChange, + emitOpen: this._openRoom.bind(this) }); }); this._roomList = roomTileVMs.sortValues((a, b) => a.compare(b)); @@ -62,7 +63,11 @@ export class SessionViewModel extends ViewModel { } } - _openRoom(room) { + _openRoom(room, roomTileVM) { + if (this._currentRoomTileViewModel) { + this._currentRoomTileViewModel.close(); + } + this._currentRoomTileViewModel = roomTileVM; if (this._currentRoomViewModel) { this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel); } diff --git a/src/domain/session/roomlist/RoomTileViewModel.js b/src/domain/session/roomlist/RoomTileViewModel.js index 1de7f1d8..d1585262 100644 --- a/src/domain/session/roomlist/RoomTileViewModel.js +++ b/src/domain/session/roomlist/RoomTileViewModel.js @@ -15,20 +15,33 @@ limitations under the License. */ import {avatarInitials} from "../avatar.js"; +import {ViewModel} from "../../ViewModel.js"; -export class RoomTileViewModel { +export class RoomTileViewModel extends ViewModel { // we use callbacks to parent VM instead of emit because // it would be annoying to keep track of subscriptions in // parent for all RoomTileViewModels // emitUpdate is ObservableMap/ObservableList update mechanism - constructor({room, emitUpdate, emitOpen}) { + constructor(options) { + super(options); + const {room, emitOpen} = options; this._room = room; - this._emitUpdate = emitUpdate; this._emitOpen = emitOpen; + this._isOpen = false; + } + + // called by parent for now (later should integrate with router) + close() { + if (this._isOpen) { + this._isOpen = false; + this.emitChange("isOpen"); + } } open() { - this._emitOpen(this._room); + this._isOpen = true; + this.emitChange("isOpen"); + this._emitOpen(this._room, this); } compare(other) { @@ -36,6 +49,10 @@ export class RoomTileViewModel { return this._room.name.localeCompare(other._room.name); } + get isOpen() { + return this._isOpen; + } + get name() { return this._room.name; } diff --git a/src/ui/web/session/RoomTile.js b/src/ui/web/session/RoomTile.js index 036fca1b..bdce01cc 100644 --- a/src/ui/web/session/RoomTile.js +++ b/src/ui/web/session/RoomTile.js @@ -18,7 +18,7 @@ import {TemplateView} from "../general/TemplateView.js"; export class RoomTile extends TemplateView { render(t) { - return t.li([ + return t.li({"className": {"active": vm => vm.isOpen}}, [ t.div({className: "avatar medium"}, vm => vm.avatarInitials), t.div({className: "description"}, t.div({className: "name"}, vm => vm.name)) ]); From 68574715dc9f7869693dc1dadd6121b55aed4d37 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Wed, 12 Aug 2020 17:41:46 +0200 Subject: [PATCH 4/4] style active room --- src/ui/web/css/themes/element/theme.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ui/web/css/themes/element/theme.css b/src/ui/web/css/themes/element/theme.css index 3bdd8f02..36cc0d77 100644 --- a/src/ui/web/css/themes/element/theme.css +++ b/src/ui/web/css/themes/element/theme.css @@ -46,6 +46,11 @@ limitations under the License. align-items: center; } +.LeftPanel li.active { + background: lightgray; + color: black; +} + .LeftPanel li { border-bottom: 1px #555 solid; } @@ -66,7 +71,6 @@ a { color: white; } - .SessionStatusView { padding: 5px; background-color: #555;