Merge pull request #3563 from thornbill/history-router

Use history for app router
This commit is contained in:
Bill Thornton 2022-04-21 12:21:30 -04:00 committed by GitHub
commit 6412156210
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 62 additions and 120 deletions

35
package-lock.json generated
View File

@ -2083,7 +2083,6 @@
"version": "7.13.10",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz",
"integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==",
"dev": true,
"requires": {
"regenerator-runtime": "^0.13.4"
}
@ -7020,6 +7019,14 @@
"resolved": "https://registry.npmjs.org/headroom.js/-/headroom.js-0.12.0.tgz",
"integrity": "sha512-iXnAafUm3FdzfJ91uixLws2hkKI1jC8bAKK/pt7XYr8Ie1jO7xbK48Ycpl9tUPyBgkzuj1p/PhJS0fy4E/5anA=="
},
"history": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz",
"integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==",
"requires": {
"@babel/runtime": "^7.7.6"
}
},
"hls.js": {
"version": "0.14.17",
"resolved": "https://registry.npmjs.org/hls.js/-/hls.js-0.14.17.tgz",
@ -8902,14 +8909,6 @@
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
"page": {
"version": "1.11.6",
"resolved": "https://registry.npmjs.org/page/-/page-1.11.6.tgz",
"integrity": "sha512-P6e2JfzkBrPeFCIPplLP7vDDiU84RUUZMrWdsH4ZBGJ8OosnwFkcUkBHp1DTIjuipLliw9yQn/ZJsXZvarsO+g==",
"requires": {
"path-to-regexp": "~1.2.1"
}
},
"pako": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
@ -9016,21 +9015,6 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"path-to-regexp": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.2.1.tgz",
"integrity": "sha1-szcFwUAjTYc8hyHHuf2LVB7Tr/k=",
"requires": {
"isarray": "0.0.1"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
}
}
},
"path-type": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@ -10841,8 +10825,7 @@
"regenerator-runtime": {
"version": "0.13.7",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==",
"dev": true
"integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew=="
},
"regenerator-transform": {
"version": "0.14.5",

View File

@ -80,6 +80,7 @@
"fast-text-encoding": "1.0.3",
"flv.js": "1.6.2",
"headroom.js": "0.12.0",
"history": "5.3.0",
"hls.js": "0.14.17",
"intersection-observer": "0.12.0",
"jellyfin-apiclient": "1.10.0",
@ -91,7 +92,6 @@
"marked": "4.0.10",
"material-design-icons-iconfont": "6.1.1",
"native-promise-only": "0.8.1",
"page": "1.11.6",
"pdfjs-dist": "2.12.313",
"react": "17.0.2",
"react-dom": "17.0.2",

View File

@ -1,20 +1,22 @@
import { Events } from 'jellyfin-apiclient';
import { Action, createHashHistory } from 'history';
import { appHost } from './apphost';
import appSettings from '../scripts/settings/appSettings';
import { clearBackdrop, setBackdropTransparency } from './backdrop/backdrop';
import browser from '../scripts/browser';
import { Events } from 'jellyfin-apiclient';
import globalize from '../scripts/globalize';
import itemHelper from './itemHelper';
import loading from './loading/loading';
import page from 'page';
import viewManager from './viewManager/viewManager';
import Dashboard from '../utils/dashboard';
import ServerConnections from './ServerConnections';
import alert from './alert';
import reactControllerFactory from './reactControllerFactory';
const history = createHashHistory();
class AppRouter {
allRoutes = [];
allRoutes = new Map();
backdropContainer;
backgroundContainer;
currentRouteInfo;
@ -23,7 +25,6 @@ class AppRouter {
forcedLogoutMsg;
isDummyBackToHome;
msgTimeout;
popstateOccurred = false;
promiseShow;
resolveOnNextShow;
previousRoute = {};
@ -33,58 +34,24 @@ class AppRouter {
startPages = ['home', 'login', 'selectserver'];
constructor() {
// WebKit fires a popstate event on document load
// Skip it using boolean
// For Tizen 2.x
// See `page` node module
let loaded = document.readyState === 'complete';
if (!loaded) {
window.addEventListener('load', () => {
setTimeout(() => {
loaded = true;
}, 0);
});
}
window.addEventListener('popstate', () => {
if (!loaded) return;
this.popstateOccurred = true;
});
document.addEventListener('viewshow', () => this.onViewShow());
// TODO: Can this baseRoute logic be simplified?
this.baseRoute = window.location.href.split('?')[0].replace(this.getRequestFile(), '');
// support hashbang
this.baseRoute = this.baseRoute.split('#')[0];
if (this.baseRoute.endsWith('/') && !this.baseRoute.endsWith('://')) {
this.baseRoute = this.baseRoute.substring(0, this.baseRoute.length - 1);
}
}
this.setBaseRoute();
// paths that start with a hashbang (i.e. /#!/page.html) get transformed to starting with //
// we need to strip one "/" for our routes to work
page('//*', (ctx) => {
page.redirect(ctx.path.substring(1));
addRoute(path, route) {
this.allRoutes.set(path, {
route,
handler: this.#getHandler(route)
});
}
/**
* @private
*/
setBaseRoute() {
let baseRoute = window.location.pathname.replace(this.getRequestFile(), '');
if (baseRoute.lastIndexOf('/') === baseRoute.length - 1) {
baseRoute = baseRoute.substring(0, baseRoute.length - 1);
}
console.debug('setting page base to ' + baseRoute);
page.base(baseRoute);
}
addRoute(path, newRoute) {
page(path, this.getHandler(newRoute));
this.allRoutes.push(newRoute);
}
showLocalLogin(serverId) {
Dashboard.navigate('login.html?serverid=' + serverId);
}
@ -124,7 +91,7 @@ class AppRouter {
this.promiseShow = new Promise((resolve) => {
this.resolveOnNextShow = resolve;
page.back();
history.back();
});
return this.promiseShow;
@ -155,7 +122,7 @@ class AppRouter {
this.promiseShow = new Promise((resolve) => {
this.resolveOnNextShow = resolve;
// Schedule a call to return the promise
setTimeout(() => page.show(path, options), 0);
setTimeout(() => history.push(path, options), 0);
});
return this.promiseShow;
@ -167,27 +134,50 @@ class AppRouter {
this.promiseShow = new Promise((resolve) => {
this.resolveOnNextShow = resolve;
// Schedule a call to return the promise
setTimeout(() => page.show(this.baseUrl() + path), 0);
setTimeout(() => history.push(this.baseUrl() + path), 0);
});
return this.promiseShow;
}
start(options) {
#goToRoute({ location, action }) {
// Strip the leading "!" if present
const normalizedPath = location.pathname.replace(/^!/, '');
const route = this.allRoutes.get(normalizedPath);
if (route) {
console.debug('[appRouter] "%s" route found', normalizedPath, location, route);
route.handler({
// Recreate the default context used by page.js: https://github.com/visionmedia/page.js#context
path: normalizedPath + location.search,
pathname: normalizedPath,
querystring: location.search.replace(/^\?/, ''),
state: location.state,
// Custom context variables
isBack: action === Action.Pop
});
} else {
console.warn('[appRouter] "%s" route not found', normalizedPath, location);
}
}
start() {
loading.show();
this.initApiClients();
Events.on(appHost, 'beforeexit', this.onBeforeExit);
Events.on(appHost, 'resume', this.onAppResume);
ServerConnections.connect({
enableAutoLogin: appSettings.enableAutoLogin()
}).then((result) => {
this.firstConnectionResult = result;
options = options || {};
page({
click: options.click !== false,
hashbang: options.hashbang !== false
// Handle the initial route
this.#goToRoute({ location: history.location });
// Handle route changes
history.listen(params => {
this.#goToRoute(params);
});
}).catch().then(() => {
loading.hide();
@ -262,19 +252,6 @@ class AppRouter {
setBackdropTransparency(level);
}
getRoutes() {
return this.allRoutes;
}
pushState(state, title, url) {
state.navigate = false;
window.history.pushState(state, title, url);
}
enableNativeHistory() {
return false;
}
handleConnectionResult(result) {
switch (result.State) {
case 'SignedIn':
@ -452,12 +429,6 @@ class AppRouter {
}
}
onBeforeExit() {
if (browser.web0s) {
page.restorePreviousState();
}
}
normalizeImageOptions(options) {
let setQuality;
if (options.maxWidth || options.width || options.maxHeight || options.height || options.fillWidth || options.fillHeight) {
@ -544,12 +515,12 @@ class AppRouter {
const apiClient = ServerConnections.currentApiClient();
const pathname = ctx.pathname.toLowerCase();
console.debug('processing path request: ' + pathname);
console.debug('[appRouter] processing path request: ' + pathname);
const isCurrentRouteStartup = this.currentRouteInfo ? this.currentRouteInfo.route.startup : true;
const shouldExitApp = ctx.isBack && route.isDefaultRoute && isCurrentRouteStartup;
if (!shouldExitApp && (!apiClient || !apiClient.isLoggedIn()) && !route.anonymous) {
console.debug('route does not allow anonymous access: redirecting to login');
console.debug('[appRouter] route does not allow anonymous access: redirecting to login');
this.beginConnectionWizard();
return;
}
@ -563,10 +534,10 @@ class AppRouter {
}
if (apiClient && apiClient.isLoggedIn()) {
console.debug('user is authenticated');
console.debug('[appRouter] user is authenticated');
if (route.isDefaultRoute) {
console.debug('loading home page');
console.debug('[appRouter] loading home page');
this.goHome();
return;
} else if (route.roles) {
@ -577,7 +548,7 @@ class AppRouter {
}
}
console.debug('proceeding to page: ' + pathname);
console.debug('[appRouter] proceeding to page: ' + pathname);
callback();
}
@ -632,11 +603,8 @@ class AppRouter {
return path;
}
getHandler(route) {
#getHandler(route) {
return (ctx, next) => {
ctx.isBack = this.popstateOccurred;
this.popstateOccurred = false;
const ignore = route.dummyRoute === true || this.previousRoute.dummyRoute === true;
this.previousRoute = route;
if (ignore) {

View File

@ -566,13 +566,7 @@ import { appRouter } from '../components/appRouter';
});
defineRoute({
path: '',
isDefaultRoute: true,
autoFocus: false
});
defineRoute({
path: 'index.html',
path: '/',
autoFocus: false,
isDefaultRoute: true
});

View File

@ -163,10 +163,7 @@ async function onAppReady() {
import('../assets/css/ios.scss');
}
appRouter.start({
click: false,
hashbang: true
});
appRouter.start();
if (!browser.tv && !browser.xboxOne && !browser.ps4) {
import('../components/nowPlayingBar/nowPlayingBar');