open menu when clicking ... button on message with delete/cancel option

This commit is contained in:
Bruno Windels 2021-05-28 13:14:55 +02:00
parent 63e948fc80
commit 2b0fa22c8a
6 changed files with 70 additions and 7 deletions

View file

@ -49,12 +49,13 @@ limitations under the License.
} }
} }
.Timeline_message:hover, .Timeline_message.selected { .Timeline_message:hover, .Timeline_message.selected, .Timeline_message.menuOpen {
background-color: rgba(141, 151, 165, 0.1); background-color: rgba(141, 151, 165, 0.1);
border-radius: 4px; border-radius: 4px;
} }
.Timeline_message:hover > .Timeline_messageOptions { .Timeline_message:hover > .Timeline_messageOptions,
.Timeline_message.menuOpen > .Timeline_messageOptions {
display: block; display: block;
} }

View file

@ -30,13 +30,14 @@ const VerticalAxis = {
}; };
export class Popup { export class Popup {
constructor(view) { constructor(view, closeCallback = null) {
this._view = view; this._view = view;
this._target = null; this._target = null;
this._arrangement = null; this._arrangement = null;
this._scroller = null; this._scroller = null;
this._fakeRoot = null; this._fakeRoot = null;
this._trackingTemplateView = null; this._trackingTemplateView = null;
this._closeCallback = closeCallback;
} }
trackInTemplateView(templateView) { trackInTemplateView(templateView) {
@ -82,6 +83,9 @@ export class Popup {
document.body.removeEventListener("click", this, false); document.body.removeEventListener("click", this, false);
this._popup.remove(); this._popup.remove();
this._view = null; this._view = null;
if (this._closeCallback) {
this._closeCallback();
}
} }
} }

View file

@ -45,6 +45,7 @@ export class TimelineList extends ListView {
const options = { const options = {
className: "Timeline bottom-aligned-scroll", className: "Timeline bottom-aligned-scroll",
list: viewModel.tiles, list: viewModel.tiles,
onItemClick: (tileView, evt) => tileView.onClick(evt),
} }
super(options, entry => { super(options, entry => {
const View = viewClassForEntry(entry); const View = viewClassForEntry(entry);

View file

@ -20,4 +20,7 @@ export class AnnouncementView extends TemplateView {
render(t) { render(t) {
return t.li({className: "AnnouncementView"}, t.div(vm => vm.announcement)); return t.li({className: "AnnouncementView"}, t.div(vm => vm.announcement));
} }
/* This is called by the parent ListView, which just has 1 listener for the whole list */
onClick() {}
} }

View file

@ -17,8 +17,15 @@ limitations under the License.
import {renderStaticAvatar} from "../../../avatar.js"; import {renderStaticAvatar} from "../../../avatar.js";
import {TemplateView} from "../../../general/TemplateView.js"; import {TemplateView} from "../../../general/TemplateView.js";
import {Popup} from "../../../general/Popup.js";
import {Menu} from "../../../general/Menu.js";
export class BaseMessageView extends TemplateView { export class BaseMessageView extends TemplateView {
constructor(value) {
super(value);
this._menuPopup = null;
}
render(t, vm) { render(t, vm) {
const classes = { const classes = {
"Timeline_message": true, "Timeline_message": true,
@ -36,7 +43,46 @@ export class BaseMessageView extends TemplateView {
]); ]);
} }
renderMessageBody() { /* This is called by the parent ListView, which just has 1 listener for the whole list */
onClick(evt) {
if (evt.target.className === "Timeline_messageOptions") {
this._toggleMenu(evt.target);
} }
}
_toggleMenu(button) {
if (this._menuPopup && this._menuPopup.isOpen) {
this._menuPopup.close();
} else {
const options = this.createMenuOptions(this.value);
if (!options.length) {
return;
}
this.root().classList.add("menuOpen");
this._menuPopup = new Popup(new Menu(options), () => this.root().classList.remove("menuOpen"));
this._menuPopup.trackInTemplateView(this);
this._menuPopup.showRelativeTo(button, {
horizontal: {
relativeTo: "end",
align: "start",
after: 0
},
vertical: {
relativeTo: "start",
align: "end",
before: -24
}
});
}
}
createMenuOptions(vm) {
const options = [];
if (vm.shape !== "redacted") {
options.push(Menu.option(vm.i18n`Delete`, () => vm.redact()));
}
return options;
}
renderMessageBody() {}
} }

View file

@ -15,10 +15,18 @@ limitations under the License.
*/ */
import {BaseMessageView} from "./BaseMessageView.js"; import {BaseMessageView} from "./BaseMessageView.js";
import {Menu} from "../../../general/Menu.js";
export class RedactedView extends BaseMessageView { export class RedactedView extends BaseMessageView {
renderMessageBody(t, vm) { renderMessageBody(t, vm) {
const cancelButton = t.if(vm => vm.isRedacting, t => t.button({onClick: () => vm.abortPendingRedaction()}, "Cancel")); return t.p({className: "Timeline_messageBody statusMessage"}, vm => vm.description);
return t.p({className: "Timeline_messageBody statusMessage"}, [vm => vm.description, " ", cancelButton]); }
createMenuOptions(vm) {
const options = super.createMenuOptions(vm);
if (vm.isRedacting) {
options.push(Menu.option(vm.i18n`Cancel`, () => vm.abortPendingRedaction()));
}
return options;
} }
} }