Skip to content

Commit

Permalink
[BUGFIX] Recalculate context-menu position after data population
Browse files Browse the repository at this point in the history
With #103197, a loading indicator was added to the context menus,
which rendered a stub context-menu.
The position of the context-menu needs to be recalculated once the
data has been loaded (the context-menu becomes taller) in order to
avoid rendering outside the visible window area.

Releases: main, 12.4
Resolves: #103382
Related: #103197
Related: #103294
Change-Id: I75e3659c619d4b98c773faa4dab9bbf184471065
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/83454
Tested-by: Benjamin Franzke <ben@bnf.dev>
Reviewed-by: Benjamin Franzke <ben@bnf.dev>
Tested-by: core-ci <typo3@b13.com>
  • Loading branch information
bnf committed Mar 13, 2024
1 parent 3709afe commit 93c8520
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 6 deletions.
17 changes: 12 additions & 5 deletions Build/Sources/TypeScript/backend/context-menu.ts
Expand Up @@ -279,7 +279,7 @@ class ContextMenu {
(new AjaxRequest(url)).withQueryArguments(parameters).get().then(async (response: AjaxResponse): Promise<void> => {
const data: MenuItems = await response.resolve();
if (typeof response !== 'undefined' && Object.keys(response).length > 0) {
this.populateData(data, 0);
this.populateData(data, 0, position);
}
}).catch((): void => {
this.hide(stubMenu);
Expand All @@ -291,7 +291,7 @@ class ContextMenu {
if (contentMenuCurrent !== null) {
contentMenuCurrent.replaceChildren(document.createRange().createContextualFragment('<typo3-backend-spinner size="medium"></typo3-backend-spinner>'));
contentMenuCurrent.style.display = null;
position ??= this.getPosition(contentMenuCurrent);
position = this.getPosition(contentMenuCurrent, position);
const coordinates = this.toPixel(position);

contentMenuCurrent.style.top = coordinates.top;
Expand All @@ -308,7 +308,7 @@ class ContextMenu {
* @param {MenuItems} items The data that will be put in the menu
* @param {number} level The depth of the context menu
*/
private populateData(items: MenuItems, level: number): void {
private populateData(items: MenuItems, level: number, position: MousePosition): void {
const contentMenuCurrent = document.querySelector('#contentMenu' + level) as HTMLElement;
const contentMenuParent = document.querySelector('#contentMenu' + (level - 1)) as HTMLElement;
if (contentMenuCurrent !== null && contentMenuParent?.offsetParent !== null) {
Expand All @@ -321,6 +321,10 @@ class ContextMenu {

contentMenuCurrent.innerHTML = '';
contentMenuCurrent.appendChild(menuGroup);
position = this.getPosition(contentMenuCurrent, position);
const coordinates = this.toPixel(position);
contentMenuCurrent.style.top = coordinates.top;
contentMenuCurrent.style.insetInlineStart = coordinates.start;
contentMenuCurrent.style.display = null;
(contentMenuCurrent.querySelector('.context-menu-item[tabindex="-1"]') as HTMLElement).focus();
this.initializeEvents(contentMenuCurrent, level);
Expand Down Expand Up @@ -494,7 +498,7 @@ class ContextMenu {
return { start: Math.round(position.X) + 'px', top: Math.round(position.Y) + 'px' };
}

private getPosition(element: HTMLElement): MousePosition {
private getPosition(element: HTMLElement, position: MousePosition = null): MousePosition {

const space = 10;
const offset = 5;
Expand All @@ -515,7 +519,10 @@ class ContextMenu {
start : number = 0,
top : number = 0;

if (origin !== undefined && origin !== null) {
if (position !== null) {
top = position.Y;
start = direction === 'ltr' ? position.X : windowDimentions.width - position.X;
} else if (origin !== undefined && origin !== null) {
const boundingRect = origin.getBoundingClientRect();
top = boundingRect.y;
start = direction === 'ltr' ? boundingRect.x + boundingRect.width : windowDimentions.width - boundingRect.x;
Expand Down

0 comments on commit 93c8520

Please sign in to comment.