FIX: allows to resize panels on tablets (#22640)

On tablets like iPad where we allow channel and thread to be on the same screen, it was not possible to resize the panels due to code being thought for mouse events. This commit should now correctly allow for this.

The "resizer" has also been made larger to simplify touching.

No test as it's hard to test on iPad and dragging events are also complex.
This commit is contained in:
Joffrey JAFFEUX 2023-07-17 15:11:51 +02:00 committed by GitHub
parent fe8d9b6b4e
commit a982b6765f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 85 additions and 29 deletions

View File

@ -1,10 +1,13 @@
import Modifier from "ember-modifier"; import Modifier from "ember-modifier";
import { registerDestructor } from "@ember/destroyable"; import { registerDestructor } from "@ember/destroyable";
import { bind } from "discourse-common/utils/decorators"; import { bind } from "discourse-common/utils/decorators";
import { inject as service } from "@ember/service";
const MINIMUM_SIZE = 20; const MINIMUM_SIZE = 20;
export default class ResizableNode extends Modifier { export default class ResizableNode extends Modifier {
@service capabilities;
element = null; element = null;
resizerSelector = null; resizerSelector = null;
didResizeContainer = null; didResizeContainer = null;
@ -14,8 +17,8 @@ export default class ResizableNode extends Modifier {
_originalHeight = 0; _originalHeight = 0;
_originalX = 0; _originalX = 0;
_originalY = 0; _originalY = 0;
_originalMouseX = 0; _originalPageX = 0;
_originalMouseY = 0; _originalPageY = 0;
constructor(owner, args) { constructor(owner, args) {
super(owner, args); super(owner, args);
@ -31,15 +34,27 @@ export default class ResizableNode extends Modifier {
options options
); );
this.element if (this.capabilities.touch) {
.querySelector(this.resizerSelector) this.element
?.addEventListener("mousedown", this._startResize); .querySelector(this.resizerSelector)
?.addEventListener("touchstart", this._startResize);
} else {
this.element
.querySelector(this.resizerSelector)
?.addEventListener("mousedown", this._startResize);
}
} }
cleanup() { cleanup() {
this.element if (this.capabilities.touch) {
.querySelector(this.resizerSelector) this.element
?.removeEventListener("mousedown", this._startResize); .querySelector(this.resizerSelector)
?.addEventListener("touchstart", this._startResize);
} else {
this.element
.querySelector(this.resizerSelector)
?.removeEventListener("mousedown", this._startResize);
}
} }
@bind @bind
@ -58,19 +73,25 @@ export default class ResizableNode extends Modifier {
); );
this._originalX = this.element.getBoundingClientRect().left; this._originalX = this.element.getBoundingClientRect().left;
this._originalY = this.element.getBoundingClientRect().top; this._originalY = this.element.getBoundingClientRect().top;
this._originalMouseX = event.pageX;
this._originalMouseY = event.pageY;
window.addEventListener("mousemove", this._resize); this._originalPageX = this._eventValueForProperty(event, "pageX");
window.addEventListener("mouseup", this._stopResize); this._originalPageY = this._eventValueForProperty(event, "pageY");
if (this.capabilities.touch) {
window.addEventListener("touchmove", this._resize);
window.addEventListener("touchend", this._stopResize);
} else {
window.addEventListener("mousemove", this._resize);
window.addEventListener("mouseup", this._stopResize);
}
} }
/* /*
The bulk of the logic is to calculate the new width and height of the element The bulk of the logic is to calculate the new width and height of the element
based on the current mouse position: width is calculated by subtracting based on the current position on page: width is calculated by subtracting
the difference between the current event.pageX and the original this._originalMouseX the difference between the current pageX and the original this._originalPageX
from the original this._originalWidth, and rounding up to the nearest integer. from the original this._originalWidth, and rounding up to the nearest integer.
height is calculated in a similar way using event.pageY and this._originalMouseY. height is calculated in a similar way using pageY and this._originalPageY.
In this example (B) is the current element top/left and (A) is x/y of the mouse after dragging: In this example (B) is the current element top/left and (A) is x/y of the mouse after dragging:
@ -83,7 +104,8 @@ export default class ResizableNode extends Modifier {
@bind @bind
_resize(event) { _resize(event) {
let width = this._originalWidth; let width = this._originalWidth;
let diffWidth = event.pageX - this._originalMouseX; let diffWidth =
this._eventValueForProperty(event, "pageX") - this._originalPageX;
if (document.documentElement.classList.contains("rtl")) { if (document.documentElement.classList.contains("rtl")) {
width = Math.ceil(width + diffWidth); width = Math.ceil(width + diffWidth);
} else { } else {
@ -91,7 +113,8 @@ export default class ResizableNode extends Modifier {
} }
const height = Math.ceil( const height = Math.ceil(
this._originalHeight - (event.pageY - this._originalMouseY) this._originalHeight -
(this._eventValueForProperty(event, "pageY") - this._originalPageY)
); );
const newStyle = {}; const newStyle = {};
@ -101,8 +124,11 @@ export default class ResizableNode extends Modifier {
if (this.options.position) { if (this.options.position) {
newStyle.left = newStyle.left =
Math.ceil(this._originalX + (event.pageX - this._originalMouseX)) + Math.ceil(
"px"; this._originalX +
(this._eventValueForProperty(event, "pageX") -
this._originalPageX)
) + "px";
} }
} }
@ -111,8 +137,11 @@ export default class ResizableNode extends Modifier {
if (this.options.position) { if (this.options.position) {
newStyle.top = newStyle.top =
Math.ceil(this._originalY + (event.pageY - this._originalMouseY)) + Math.ceil(
"px"; this._originalY +
(this._eventValueForProperty(event, "pageY") -
this._originalPageY)
) + "px";
} }
} }
@ -125,7 +154,20 @@ export default class ResizableNode extends Modifier {
@bind @bind
_stopResize() { _stopResize() {
window.removeEventListener("mousemove", this._resize); if (this.capabilities.touch) {
window.removeEventListener("mouseup", this._stopResize); window.removeEventListener("touchmove", this._resize);
window.removeEventListener("touchend", this._stopResize);
} else {
window.removeEventListener("mousemove", this._resize);
window.removeEventListener("mouseup", this._stopResize);
}
}
_eventValueForProperty(event, property) {
if (this.capabilities.touch) {
return event.changedTouches[0][property];
} else {
return event[property];
}
} }
} }

View File

@ -1,16 +1,30 @@
.chat-side-panel-resizer { .chat-side-panel-resizer {
top: 0; top: 0;
bottom: 0; bottom: 0;
left: -3px;
width: 5px;
position: absolute; position: absolute;
z-index: calc(z("header") - 1); z-index: calc(z("header") - 1);
transition: background-color 0.15s 0.15s; transition: background-color 0.15s 0.15s;
background-color: transparent; background-color: transparent;
&:hover, .touch & {
&:active { left: -6px;
cursor: col-resize; width: 10px;
background: var(--tertiary);
&:active {
cursor: col-resize;
background: var(--tertiary);
}
}
.no-touch & {
left: -3px;
width: 5px;
&:hover,
&:active {
cursor: col-resize;
background: var(--tertiary);
}
} }
} }