mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-17 19:08:18 -07:00
Merge pull request #3620 from thornbill/update-dialog-routing
Update dialog history handling
This commit is contained in:
commit
1dbbb4c65d
@ -11,7 +11,7 @@ import ServerConnections from './ServerConnections';
|
|||||||
import alert from './alert';
|
import alert from './alert';
|
||||||
import reactControllerFactory from './reactControllerFactory';
|
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).
|
* 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 {
|
class AppRouter {
|
||||||
allRoutes = new Map();
|
allRoutes = new Map();
|
||||||
currentRouteInfo;
|
currentRouteInfo = { route: {} };
|
||||||
currentViewLoadRequest;
|
currentViewLoadRequest;
|
||||||
firstConnectionResult;
|
firstConnectionResult;
|
||||||
forcedLogoutMsg;
|
forcedLogoutMsg;
|
||||||
msgTimeout;
|
msgTimeout;
|
||||||
promiseShow;
|
promiseShow;
|
||||||
resolveOnNextShow;
|
resolveOnNextShow;
|
||||||
previousRoute = {};
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
document.addEventListener('viewshow', () => this.onViewShow());
|
document.addEventListener('viewshow', () => this.onViewShow());
|
||||||
@ -482,9 +481,9 @@ class AppRouter {
|
|||||||
|
|
||||||
#getHandler(route) {
|
#getHandler(route) {
|
||||||
return (ctx, next) => {
|
return (ctx, next) => {
|
||||||
const ignore = route.dummyRoute === true || this.previousRoute.dummyRoute === true;
|
const ignore = ctx.path === this.currentRouteInfo.path;
|
||||||
this.previousRoute = route;
|
|
||||||
if (ignore) {
|
if (ignore) {
|
||||||
|
console.debug('[appRouter] path did not change, ignoring route change');
|
||||||
// Resolve 'show' promise
|
// Resolve 'show' promise
|
||||||
this.onViewShow();
|
this.onViewShow();
|
||||||
return;
|
return;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { appRouter } from '../appRouter';
|
import { history } from '../appRouter';
|
||||||
import focusManager from '../focusManager';
|
import focusManager from '../focusManager';
|
||||||
import browser from '../../scripts/browser';
|
import browser from '../../scripts/browser';
|
||||||
import layoutManager from '../layoutManager';
|
import layoutManager from '../layoutManager';
|
||||||
@ -39,7 +39,7 @@ import '../../assets/css/scrollstyles.scss';
|
|||||||
try {
|
try {
|
||||||
parentNode.removeChild(elem);
|
parentNode.removeChild(elem);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('error removing dialog element: ' + err);
|
console.error('[dialogHelper] error removing dialog element: ' + err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,26 +49,26 @@ import '../../assets/css/scrollstyles.scss';
|
|||||||
self.originalUrl = window.location.href;
|
self.originalUrl = window.location.href;
|
||||||
const activeElement = document.activeElement;
|
const activeElement = document.activeElement;
|
||||||
let removeScrollLockOnClose = false;
|
let removeScrollLockOnClose = false;
|
||||||
|
let unlisten;
|
||||||
|
|
||||||
function onHashChange() {
|
function onHashChange({ location }) {
|
||||||
const isBack = self.originalUrl === window.location.href;
|
const dialogs = location.state?.dialogs || [];
|
||||||
|
const shouldClose = !dialogs.includes(hash);
|
||||||
|
|
||||||
if (isBack || !isOpened(dlg)) {
|
if ((shouldClose || !isOpened(dlg)) && unlisten) {
|
||||||
window.removeEventListener('popstate', onHashChange);
|
unlisten();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isBack) {
|
if (shouldClose) {
|
||||||
self.closedByBack = true;
|
close(dlg);
|
||||||
closeDialog(dlg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onBackCommand(e) {
|
function onBackCommand(e) {
|
||||||
if (e.detail.command === 'back') {
|
if (e.detail.command === 'back') {
|
||||||
self.closedByBack = true;
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
closeDialog(dlg);
|
close(dlg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +77,9 @@ import '../../assets/css/scrollstyles.scss';
|
|||||||
inputManager.off(dlg, onBackCommand);
|
inputManager.off(dlg, onBackCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.removeEventListener('popstate', onHashChange);
|
if (unlisten) {
|
||||||
|
unlisten();
|
||||||
|
}
|
||||||
|
|
||||||
removeBackdrop(dlg);
|
removeBackdrop(dlg);
|
||||||
dlg.classList.remove('opened');
|
dlg.classList.remove('opened');
|
||||||
@ -86,10 +88,22 @@ import '../../assets/css/scrollstyles.scss';
|
|||||||
document.body.classList.remove('noScroll');
|
document.body.classList.remove('noScroll');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self.closedByBack && isHistoryEnabled(dlg)) {
|
if (isHistoryEnabled(dlg)) {
|
||||||
const state = window.history.state || {};
|
const state = history.location.state || {};
|
||||||
if (state.dialogId === hash) {
|
if (state.dialogs?.length > 0) {
|
||||||
appRouter.back();
|
if (state.dialogs[state.dialogs.length - 1] === hash) {
|
||||||
|
history.back();
|
||||||
|
} else if (state.dialogs.includes(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)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,14 +126,18 @@ import '../../assets/css/scrollstyles.scss';
|
|||||||
//resolve();
|
//resolve();
|
||||||
// if we just called history.back(), then use a timeout to allow the history events to fire first
|
// if we just called history.back(), then use a timeout to allow the history events to fire first
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
dlg.dispatchEvent(new CustomEvent('close', {
|
||||||
|
bubbles: false,
|
||||||
|
cancelable: false
|
||||||
|
}));
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
element: dlg,
|
element: dlg
|
||||||
closedByBack: self.closedByBack
|
|
||||||
});
|
});
|
||||||
}, 1);
|
}, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
dlg.addEventListener('close', onDialogClosed);
|
dlg.addEventListener('_close', onDialogClosed);
|
||||||
|
|
||||||
const center = !dlg.classList.contains('dialog-fixedSize');
|
const center = !dlg.classList.contains('dialog-fixedSize');
|
||||||
if (center) {
|
if (center) {
|
||||||
@ -144,9 +162,20 @@ import '../../assets/css/scrollstyles.scss';
|
|||||||
animateDialogOpen(dlg);
|
animateDialogOpen(dlg);
|
||||||
|
|
||||||
if (isHistoryEnabled(dlg)) {
|
if (isHistoryEnabled(dlg)) {
|
||||||
appRouter.show(`/dialog?dlg=${hash}`, { dialogId: hash });
|
const state = history.location.state || {};
|
||||||
|
const dialogs = state.dialogs || [];
|
||||||
|
// Add new dialog to the list of open dialogs
|
||||||
|
dialogs.push(hash);
|
||||||
|
|
||||||
window.addEventListener('popstate', onHashChange);
|
history.push(
|
||||||
|
`${history.location.pathname}${history.location.search}`,
|
||||||
|
{
|
||||||
|
...state,
|
||||||
|
dialogs
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
unlisten = history.listen(onHashChange);
|
||||||
} else {
|
} else {
|
||||||
inputManager.on(dlg, onBackCommand);
|
inputManager.on(dlg, onBackCommand);
|
||||||
}
|
}
|
||||||
@ -213,16 +242,6 @@ import '../../assets/css/scrollstyles.scss';
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function close(dlg) {
|
export function close(dlg) {
|
||||||
if (isOpened(dlg)) {
|
|
||||||
if (isHistoryEnabled(dlg)) {
|
|
||||||
appRouter.back();
|
|
||||||
} else {
|
|
||||||
closeDialog(dlg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeDialog(dlg) {
|
|
||||||
if (!dlg.classList.contains('hide')) {
|
if (!dlg.classList.contains('hide')) {
|
||||||
dlg.dispatchEvent(new CustomEvent('closing', {
|
dlg.dispatchEvent(new CustomEvent('closing', {
|
||||||
bubbles: false,
|
bubbles: false,
|
||||||
@ -233,7 +252,7 @@ import '../../assets/css/scrollstyles.scss';
|
|||||||
focusManager.popScope(dlg);
|
focusManager.popScope(dlg);
|
||||||
|
|
||||||
dlg.classList.add('hide');
|
dlg.classList.add('hide');
|
||||||
dlg.dispatchEvent(new CustomEvent('close', {
|
dlg.dispatchEvent(new CustomEvent('_close', {
|
||||||
bubbles: false,
|
bubbles: false,
|
||||||
cancelable: false
|
cancelable: false
|
||||||
}));
|
}));
|
||||||
@ -348,7 +367,7 @@ import '../../assets/css/scrollstyles.scss';
|
|||||||
if (enableAnimation()) {
|
if (enableAnimation()) {
|
||||||
backdrop.classList.remove('dialogBackdropOpened');
|
backdrop.classList.remove('dialogBackdropOpened');
|
||||||
|
|
||||||
// this is not firing animatonend
|
// this is not firing animationend
|
||||||
setTimeout(onAnimationFinish, 300);
|
setTimeout(onAnimationFinish, 300);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1088,9 +1088,7 @@ import template from './metadataEditor.template.html';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
show: function (itemId, serverId) {
|
show: function (itemId, serverId) {
|
||||||
return new Promise(function (resolve) {
|
return new Promise(resolve => show(itemId, serverId, resolve));
|
||||||
return show(itemId, serverId, resolve);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
embed: function (elem, itemId, serverId) {
|
embed: function (elem, itemId, serverId) {
|
||||||
|
@ -560,11 +560,6 @@ import { appRouter } from '../components/appRouter';
|
|||||||
serverRequest: true
|
serverRequest: true
|
||||||
});
|
});
|
||||||
|
|
||||||
defineRoute({
|
|
||||||
path: '/dialog',
|
|
||||||
dummyRoute: true
|
|
||||||
});
|
|
||||||
|
|
||||||
defineRoute({
|
defineRoute({
|
||||||
path: '/',
|
path: '/',
|
||||||
autoFocus: false,
|
autoFocus: false,
|
||||||
|
Loading…
Reference in New Issue
Block a user