From c49f53257c73359c5e7e40eb6d9195dfc24e4dc7 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Wed, 27 Apr 2022 15:14:35 -0400 Subject: [PATCH 1/7] Update dialog history handling --- src/components/appRouter.js | 9 ++-- src/components/dialogHelper/dialogHelper.js | 54 +++++++++++---------- src/scripts/routes.js | 5 -- 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/src/components/appRouter.js b/src/components/appRouter.js index a75d8823df..2119d2095e 100644 --- a/src/components/appRouter.js +++ b/src/components/appRouter.js @@ -11,7 +11,7 @@ import ServerConnections from './ServerConnections'; import alert from './alert'; import reactControllerFactory from './reactControllerFactory'; -const history = createHashHistory(); +export const history = createHashHistory(); /** * Page types of "no return" (when "Go back" should behave differently, probably quitting the application). @@ -20,14 +20,13 @@ const START_PAGE_TYPES = ['home', 'login', 'selectserver']; class AppRouter { allRoutes = new Map(); - currentRouteInfo; + currentRouteInfo = { route: {} }; currentViewLoadRequest; firstConnectionResult; forcedLogoutMsg; msgTimeout; promiseShow; resolveOnNextShow; - previousRoute = {}; constructor() { document.addEventListener('viewshow', () => this.onViewShow()); @@ -482,9 +481,9 @@ class AppRouter { #getHandler(route) { return (ctx, next) => { - const ignore = route.dummyRoute === true || this.previousRoute.dummyRoute === true; - this.previousRoute = route; + const ignore = ctx.path === this.currentRouteInfo.path; if (ignore) { + console.debug('[appRouter] path did not change, ignoring route change'); // Resolve 'show' promise this.onViewShow(); return; diff --git a/src/components/dialogHelper/dialogHelper.js b/src/components/dialogHelper/dialogHelper.js index 59b249b8f5..aa41043476 100644 --- a/src/components/dialogHelper/dialogHelper.js +++ b/src/components/dialogHelper/dialogHelper.js @@ -1,4 +1,4 @@ -import { appRouter } from '../appRouter'; +import { history } from '../appRouter'; import focusManager from '../focusManager'; import browser from '../../scripts/browser'; import layoutManager from '../layoutManager'; @@ -49,17 +49,19 @@ import '../../assets/css/scrollstyles.scss'; self.originalUrl = window.location.href; const activeElement = document.activeElement; let removeScrollLockOnClose = false; + let unlisten; - function onHashChange() { - const isBack = self.originalUrl === window.location.href; + function onHashChange({ location }) { + const dialogs = location.state?.dialogs || []; + const shouldClose = !dialogs.includes(hash); - if (isBack || !isOpened(dlg)) { - window.removeEventListener('popstate', onHashChange); + if ((shouldClose || !isOpened(dlg)) && unlisten) { + unlisten(); } - if (isBack) { + if (shouldClose) { self.closedByBack = true; - closeDialog(dlg); + close(dlg); } } @@ -68,7 +70,7 @@ import '../../assets/css/scrollstyles.scss'; self.closedByBack = true; e.preventDefault(); e.stopPropagation(); - closeDialog(dlg); + close(dlg); } } @@ -77,7 +79,9 @@ import '../../assets/css/scrollstyles.scss'; inputManager.off(dlg, onBackCommand); } - window.removeEventListener('popstate', onHashChange); + if (unlisten) { + unlisten(); + } removeBackdrop(dlg); dlg.classList.remove('opened'); @@ -86,10 +90,10 @@ import '../../assets/css/scrollstyles.scss'; document.body.classList.remove('noScroll'); } - if (!self.closedByBack && isHistoryEnabled(dlg)) { - const state = window.history.state || {}; - if (state.dialogId === hash) { - appRouter.back(); + if (isHistoryEnabled(dlg)) { + const state = history.location.state || {}; + if (state.dialogs?.length > 0 && state.dialogs[0] === hash) { + history.back(); } } @@ -144,9 +148,19 @@ import '../../assets/css/scrollstyles.scss'; animateDialogOpen(dlg); if (isHistoryEnabled(dlg)) { - appRouter.show(`/dialog?dlg=${hash}`, { dialogId: hash }); + const state = history.location.state || {}; + const dialogs = state.dialogs || []; + dialogs.push(hash); - window.addEventListener('popstate', onHashChange); + history.push( + `${history.location.pathname}${history.location.search}`, + { + ...state, + dialogs + } + ); + + unlisten = history.listen(onHashChange); } else { inputManager.on(dlg, onBackCommand); } @@ -213,16 +227,6 @@ import '../../assets/css/scrollstyles.scss'; } export function close(dlg) { - if (isOpened(dlg)) { - if (isHistoryEnabled(dlg)) { - appRouter.back(); - } else { - closeDialog(dlg); - } - } - } - - function closeDialog(dlg) { if (!dlg.classList.contains('hide')) { dlg.dispatchEvent(new CustomEvent('closing', { bubbles: false, diff --git a/src/scripts/routes.js b/src/scripts/routes.js index 6fd437d1cd..a96ab7a30d 100644 --- a/src/scripts/routes.js +++ b/src/scripts/routes.js @@ -560,11 +560,6 @@ import { appRouter } from '../components/appRouter'; serverRequest: true }); - defineRoute({ - path: '/dialog', - dummyRoute: true - }); - defineRoute({ path: '/', autoFocus: false, From fb48309710b6656f214cbae5376f1bcd75d46fb1 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Tue, 10 May 2022 12:40:45 -0400 Subject: [PATCH 2/7] Fix dialog adding order --- src/components/dialogHelper/dialogHelper.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/components/dialogHelper/dialogHelper.js b/src/components/dialogHelper/dialogHelper.js index aa41043476..ad64fb2e08 100644 --- a/src/components/dialogHelper/dialogHelper.js +++ b/src/components/dialogHelper/dialogHelper.js @@ -39,7 +39,7 @@ import '../../assets/css/scrollstyles.scss'; try { parentNode.removeChild(elem); } catch (err) { - console.error('error removing dialog element: ' + err); + console.error('[dialogHelper] error removing dialog element: ' + err); } } } @@ -92,8 +92,12 @@ import '../../assets/css/scrollstyles.scss'; if (isHistoryEnabled(dlg)) { const state = history.location.state || {}; - if (state.dialogs?.length > 0 && state.dialogs[0] === hash) { - history.back(); + if (state.dialogs?.length > 0) { + if (state.dialogs[0] === hash) { + history.back(); + } else if (state.dialogs.includes(hash)) { + console.info('[dialogHelper] dialog "%s" was closed, but is not the last dialog opened', hash); + } } } @@ -150,7 +154,8 @@ import '../../assets/css/scrollstyles.scss'; if (isHistoryEnabled(dlg)) { const state = history.location.state || {}; const dialogs = state.dialogs || []; - dialogs.push(hash); + // Add new dialog to start of array + dialogs.unshift(hash); history.push( `${history.location.pathname}${history.location.search}`, @@ -352,7 +357,7 @@ import '../../assets/css/scrollstyles.scss'; if (enableAnimation()) { backdrop.classList.remove('dialogBackdropOpened'); - // this is not firing animatonend + // this is not firing animationend setTimeout(onAnimationFinish, 300); return; } From 466b0dd60c636d436e4a2e44a12e8adcb0ee7cad Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Tue, 10 May 2022 13:40:47 -0400 Subject: [PATCH 3/7] Remove unused state --- src/components/dialogHelper/dialogHelper.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/dialogHelper/dialogHelper.js b/src/components/dialogHelper/dialogHelper.js index ad64fb2e08..fa307e0fda 100644 --- a/src/components/dialogHelper/dialogHelper.js +++ b/src/components/dialogHelper/dialogHelper.js @@ -60,14 +60,12 @@ import '../../assets/css/scrollstyles.scss'; } if (shouldClose) { - self.closedByBack = true; close(dlg); } } function onBackCommand(e) { if (e.detail.command === 'back') { - self.closedByBack = true; e.preventDefault(); e.stopPropagation(); close(dlg); @@ -121,8 +119,7 @@ import '../../assets/css/scrollstyles.scss'; // if we just called history.back(), then use a timeout to allow the history events to fire first setTimeout(() => { resolve({ - element: dlg, - closedByBack: self.closedByBack + element: dlg }); }, 1); } From 47d5b0eb2d6f8be0b54eca35cfd6acdcf203362c Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Tue, 10 May 2022 14:23:08 -0400 Subject: [PATCH 4/7] Reorder dialogs array --- src/components/dialogHelper/dialogHelper.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/dialogHelper/dialogHelper.js b/src/components/dialogHelper/dialogHelper.js index fa307e0fda..cd7f8b219d 100644 --- a/src/components/dialogHelper/dialogHelper.js +++ b/src/components/dialogHelper/dialogHelper.js @@ -91,7 +91,7 @@ import '../../assets/css/scrollstyles.scss'; if (isHistoryEnabled(dlg)) { const state = history.location.state || {}; if (state.dialogs?.length > 0) { - if (state.dialogs[0] === hash) { + if (state.dialogs[state.dialogs.length - 1] === hash) { history.back(); } else if (state.dialogs.includes(hash)) { console.info('[dialogHelper] dialog "%s" was closed, but is not the last dialog opened', hash); @@ -151,8 +151,8 @@ import '../../assets/css/scrollstyles.scss'; if (isHistoryEnabled(dlg)) { const state = history.location.state || {}; const dialogs = state.dialogs || []; - // Add new dialog to start of array - dialogs.unshift(hash); + // Add new dialog to the list of open dialogs + dialogs.push(hash); history.push( `${history.location.pathname}${history.location.search}`, From 54bafa5dccf160203c73c4ab302ef97632afc1ea Mon Sep 17 00:00:00 2001 From: grafixeyehero Date: Fri, 20 May 2022 03:51:36 +0300 Subject: [PATCH 5/7] Fix metadata editor dialog display --- src/components/metadataEditor/metadataEditor.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/metadataEditor/metadataEditor.js b/src/components/metadataEditor/metadataEditor.js index 3195a1c64f..749c7cac4e 100644 --- a/src/components/metadataEditor/metadataEditor.js +++ b/src/components/metadataEditor/metadataEditor.js @@ -1087,10 +1087,10 @@ import template from './metadataEditor.template.html'; } export default { - show: function (itemId, serverId) { - return new Promise(function (resolve) { - return show(itemId, serverId, resolve); - }); + show: async function (itemId, serverId) { + const apiClient = ServerConnections.getApiClient(serverId); + await apiClient.getItem(apiClient.getCurrentUserId(), itemId); + return new Promise(resolve => show(itemId, serverId, resolve)); }, embed: function (elem, itemId, serverId) { From c1739c4b7f19580b954680103963d3a2f0aee281 Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Thu, 9 Jun 2022 01:03:03 -0400 Subject: [PATCH 6/7] Use "private" close event for dialog helper race condition --- src/components/dialogHelper/dialogHelper.js | 9 +++++++-- src/components/metadataEditor/metadataEditor.js | 4 +--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/components/dialogHelper/dialogHelper.js b/src/components/dialogHelper/dialogHelper.js index cd7f8b219d..beccf23dc4 100644 --- a/src/components/dialogHelper/dialogHelper.js +++ b/src/components/dialogHelper/dialogHelper.js @@ -118,13 +118,18 @@ import '../../assets/css/scrollstyles.scss'; //resolve(); // if we just called history.back(), then use a timeout to allow the history events to fire first setTimeout(() => { + dlg.dispatchEvent(new CustomEvent('close', { + bubbles: false, + cancelable: false + })); + resolve({ element: dlg }); }, 1); } - dlg.addEventListener('close', onDialogClosed); + dlg.addEventListener('_close', onDialogClosed); const center = !dlg.classList.contains('dialog-fixedSize'); if (center) { @@ -239,7 +244,7 @@ import '../../assets/css/scrollstyles.scss'; focusManager.popScope(dlg); dlg.classList.add('hide'); - dlg.dispatchEvent(new CustomEvent('close', { + dlg.dispatchEvent(new CustomEvent('_close', { bubbles: false, cancelable: false })); diff --git a/src/components/metadataEditor/metadataEditor.js b/src/components/metadataEditor/metadataEditor.js index 749c7cac4e..10112a8453 100644 --- a/src/components/metadataEditor/metadataEditor.js +++ b/src/components/metadataEditor/metadataEditor.js @@ -1087,9 +1087,7 @@ import template from './metadataEditor.template.html'; } export default { - show: async function (itemId, serverId) { - const apiClient = ServerConnections.getApiClient(serverId); - await apiClient.getItem(apiClient.getCurrentUserId(), itemId); + show: function (itemId, serverId) { return new Promise(resolve => show(itemId, serverId, resolve)); }, From b30d371e8f6e2d0bdbb7b3e032e72d8113712d1a Mon Sep 17 00:00:00 2001 From: Bill Thornton Date: Thu, 9 Jun 2022 13:17:56 -0400 Subject: [PATCH 7/7] Update dialog history state when in invalid state --- src/components/dialogHelper/dialogHelper.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/dialogHelper/dialogHelper.js b/src/components/dialogHelper/dialogHelper.js index beccf23dc4..80b269fed5 100644 --- a/src/components/dialogHelper/dialogHelper.js +++ b/src/components/dialogHelper/dialogHelper.js @@ -94,7 +94,15 @@ import '../../assets/css/scrollstyles.scss'; if (state.dialogs[state.dialogs.length - 1] === hash) { history.back(); } else if (state.dialogs.includes(hash)) { - console.info('[dialogHelper] dialog "%s" was closed, but is not the last dialog opened', hash); + console.warn('[dialogHelper] dialog "%s" was closed, but is not the last dialog opened', hash); + // Remove the closed dialog hash from the history state + history.replace( + `${history.location.pathname}${history.location.search}`, + { + ...state, + dialogs: state.dialogs.filter(dialog => dialog !== hash) + } + ); } } }