mirror of
https://github.com/discourse/discourse.git
synced 2024-11-22 11:23:25 +08:00
FIX: ensures chat panel can't have an invalid width (#27876)
Prior to this fix the following sequence would cause an overflow:
- open a thread
- expand thread panel to maximum width
- close panel
- reduce window width
- open thread again
- 💥
The fix is now ensuring that we never use or set a width which would cause the main panel + side panel to be larger than the chat container. We also removed the service as it was overkill for this case and it's easier to have all the implementation at one place.
This commit also uses JS animation api to set the width of the panel.
<!-- NOTE: All pull requests should have tests (rspec in Ruby, qunit in JavaScript). If your code does not include test coverage, please include an explanation of why it was omitted. -->
This commit is contained in:
parent
88c2b1c01b
commit
897518e874
|
@ -1,47 +1,65 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { hash } from "@ember/helper";
|
||||
import { action } from "@ember/object";
|
||||
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
|
||||
import { service } from "@ember/service";
|
||||
import { htmlSafe } from "@ember/template";
|
||||
import { and } from "truth-helpers";
|
||||
import KeyValueStore from "discourse/lib/key-value-store";
|
||||
import resizableNode from "../modifiers/chat/resizable-node";
|
||||
import ChatSidePanelResizer from "./chat-side-panel-resizer";
|
||||
|
||||
const MIN_CHAT_CHANNEL_WIDTH = 250;
|
||||
const MIN_PANEL_WIDTH = 250;
|
||||
const STORE_NAMESPACE = "discourse_chat_side_panel_size_";
|
||||
|
||||
export default class ChatSidePanel extends Component {
|
||||
@service chatStateManager;
|
||||
@service chatSidePanelSize;
|
||||
@service site;
|
||||
|
||||
@tracked widthStyle;
|
||||
store = new KeyValueStore(STORE_NAMESPACE);
|
||||
|
||||
@action
|
||||
setupSize() {
|
||||
this.widthStyle = htmlSafe(`width:${this.chatSidePanelSize.width}px`);
|
||||
setupSize(element) {
|
||||
if (this.site.mobileView) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.chatStateManager.isFullPageActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
const validWidth = Math.min(
|
||||
this.store.getObject("width"),
|
||||
this.mainContainerWidth - MIN_PANEL_WIDTH
|
||||
);
|
||||
|
||||
element.animate(
|
||||
[{ width: element.style.width }, { width: validWidth + "px" }],
|
||||
{ duration: 0, fill: "forwards" }
|
||||
);
|
||||
this.storeWidth(validWidth);
|
||||
}
|
||||
|
||||
@action
|
||||
didResize(element, size) {
|
||||
if (this.isDestroying || this.isDestroyed) {
|
||||
return;
|
||||
}
|
||||
const mainPanelWidth = this.mainContainerWidth - size.width;
|
||||
|
||||
const parentWidth = element.parentElement.getBoundingClientRect().width;
|
||||
const mainPanelWidth = parentWidth - size.width;
|
||||
|
||||
if (mainPanelWidth >= MIN_CHAT_CHANNEL_WIDTH) {
|
||||
this.chatSidePanelSize.width = size.width;
|
||||
element.style.width = size.width + "px";
|
||||
this.widthStyle = htmlSafe(`width:${size.width}px`);
|
||||
if (size.width >= MIN_PANEL_WIDTH && mainPanelWidth >= MIN_PANEL_WIDTH) {
|
||||
element.animate(
|
||||
[{ width: element.style.width }, { width: size.width + "px" }],
|
||||
{ duration: 0, fill: "forwards" }
|
||||
);
|
||||
this.storeWidth(size.width);
|
||||
}
|
||||
}
|
||||
|
||||
#maxWidth(element) {
|
||||
const parentWidth = element.parentElement.getBoundingClientRect().width;
|
||||
return parentWidth - MIN_CHAT_CHANNEL_WIDTH;
|
||||
get mainContainerWidth() {
|
||||
return document.getElementById("main-chat-outlet").clientWidth;
|
||||
}
|
||||
|
||||
storeWidth(width) {
|
||||
this.store.setObject({
|
||||
key: "width",
|
||||
value: width,
|
||||
});
|
||||
}
|
||||
|
||||
<template>
|
||||
|
@ -56,10 +74,6 @@ export default class ChatSidePanel extends Component {
|
|||
position=false vertical=false mutate=false resetOnWindowResize=true
|
||||
)
|
||||
}}
|
||||
style={{if
|
||||
(and this.site.desktopView this.chatStateManager.isFullPageActive)
|
||||
this.widthStyle
|
||||
}}
|
||||
>
|
||||
{{yield}}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Component from "@glimmer/component";
|
||||
import { service } from "@ember/service";
|
||||
import Navbar from "discourse/plugins/chat/discourse/components/chat/navbar";
|
||||
import SidePanel from "discourse/plugins/chat/discourse/components/chat-side-panel";
|
||||
import ChatSidePanel from "discourse/plugins/chat/discourse/components/chat-side-panel";
|
||||
import FullPageChat from "discourse/plugins/chat/discourse/components/full-page-chat";
|
||||
|
||||
export default class ChatRoutesChannel extends Component {
|
||||
|
@ -32,8 +32,8 @@ export default class ChatRoutesChannel extends Component {
|
|||
/>
|
||||
</div>
|
||||
|
||||
<SidePanel>
|
||||
<ChatSidePanel>
|
||||
{{outlet}}
|
||||
</SidePanel>
|
||||
</ChatSidePanel>
|
||||
</template>
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
import Service from "@ember/service";
|
||||
import KeyValueStore from "discourse/lib/key-value-store";
|
||||
|
||||
export default class ChatSidePanelSize extends Service {
|
||||
STORE_NAMESPACE = "discourse_chat_side_panel_size_";
|
||||
MIN_WIDTH = 250;
|
||||
|
||||
store = new KeyValueStore(this.STORE_NAMESPACE);
|
||||
|
||||
get width() {
|
||||
return this.store.getObject("width") || this.MIN_WIDTH;
|
||||
}
|
||||
|
||||
set width(width) {
|
||||
this.store.setObject({
|
||||
key: "width",
|
||||
value: this.#min(width, this.MIN_WIDTH),
|
||||
});
|
||||
}
|
||||
|
||||
#min(number, min) {
|
||||
return Math.max(number, min);
|
||||
}
|
||||
}
|
|
@ -267,6 +267,7 @@ html.has-full-page-chat {
|
|||
.main-chat-outlet {
|
||||
min-height: 0;
|
||||
max-width: 100vw;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
gap: 0.25rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.dismiss-btn {
|
||||
|
|
Loading…
Reference in New Issue
Block a user