chore(vue-router): add eslint and prettier (#26636)

This commit is contained in:
Liam DeBeasi
2023-01-19 08:51:08 -05:00
committed by GitHub
parent dc27736bd5
commit 87d83bb21b
10 changed files with 4478 additions and 261 deletions

View File

@ -17,7 +17,7 @@ runs:
path: ./packages/vue
filename: VueBuild.zip
- name: Install Vue Router Dependencies
run: npm install
run: npm ci
shell: bash
working-directory: ./packages/vue-router
- name: Sync

View File

@ -0,0 +1,26 @@
module.exports = {
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"@ionic/eslint-config/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
],
"rules": {
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-non-null-assertion": "off",
"@typescript-eslint/prefer-optional-chain": "off",
"@typescript-eslint/ban-types": "off"
}
};

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,10 @@
"description": "Vue Router integration for @ionic/vue",
"scripts": {
"test.spec": "jest",
"lint": "echo add linter",
"eslint": "eslint src",
"prettier": "prettier \"./src/**/*.{html,ts,tsx,js,jsx}\"",
"lint": "npm run eslint && npm run prettier -- --write --cache",
"lint.fix": "npm run eslint -- --fix && npm run prettier -- --write --cache",
"bundle": "rollup --config rollup.config.js",
"build": "npm run clean && npm run compile && npm run bundle",
"clean": "rimraf dist",
@ -46,10 +49,16 @@
"@ionic/vue": "^6.5.0"
},
"devDependencies": {
"@ionic/eslint-config": "^0.3.0",
"@ionic/prettier-config": "^2.0.0",
"@types/jest": "^28.1.1",
"@types/node": "^14.10.1",
"@typescript-eslint/eslint-plugin": "^5.48.2",
"@typescript-eslint/parser": "^5.48.2",
"eslint": "^7.32.0",
"jest": "^28.1.1",
"jest-environment-jsdom": "^28.1.1",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
"rollup": "^2.32.1",
"ts-jest": "^28.0.5",

View File

@ -1,13 +1,14 @@
import { App } from 'vue';
import type { App } from "vue";
import {
createRouter as createVueRouter,
createWebHistory as createVueWebHistory,
createWebHashHistory as createVueWebHashHistory,
createMemoryHistory as createVueMemoryHistory
} from 'vue-router';
import { createIonRouter } from './router';
import { createViewStacks } from './viewStacks';
import { IonicVueRouterOptions } from './types';
createMemoryHistory as createVueMemoryHistory,
} from "vue-router";
import { createIonRouter } from "./router";
import type { IonicVueRouterOptions } from "./types";
import { createViewStacks } from "./viewStacks";
export const createRouter = (opts: IonicVueRouterOptions) => {
const routerOptions = { ...opts };
@ -19,8 +20,8 @@ export const createRouter = (opts: IonicVueRouterOptions) => {
const oldInstall = router.install.bind(router);
router.install = (app: App) => {
app.provide('navManager', ionRouter);
app.provide('viewStacks', viewStacks);
app.provide("navManager", ionRouter);
app.provide("viewStacks", viewStacks);
oldInstall(app);
};
@ -29,8 +30,10 @@ export const createRouter = (opts: IonicVueRouterOptions) => {
router.isReady = () => oldIsReady();
return router;
}
};
export const createWebHistory = (base?: string) => createVueWebHistory(base);
export const createWebHashHistory = (base?: string) => createVueWebHashHistory(base);
export const createMemoryHistory = (base?: string) => createVueMemoryHistory(base);
export const createWebHashHistory = (base?: string) =>
createVueWebHashHistory(base);
export const createMemoryHistory = (base?: string) =>
createVueMemoryHistory(base);

View File

@ -1,4 +1,4 @@
import { RouteInfo } from './types';
import type { RouteInfo } from "./types";
export const createLocationHistory = () => {
const locationHistory: RouteInfo[] = [];
@ -14,20 +14,22 @@ export const createLocationHistory = () => {
break;
}
if (routeInfo.routerDirection === 'root') {
if (routeInfo.routerDirection === "root") {
clearHistory();
addRoute(routeInfo);
}
}
};
const update = (routeInfo: RouteInfo) => {
const locationIndex = locationHistory.findIndex(x => x.id === routeInfo.id);
const locationIndex = locationHistory.findIndex(
(x) => x.id === routeInfo.id
);
if (locationIndex > -1) {
locationHistory.splice(locationIndex, 1, routeInfo);
}
const tabArray = tabsHistory[routeInfo.tab || ''];
const tabArray = tabsHistory[routeInfo.tab || ""];
if (tabArray) {
const tabIndex = tabArray.findIndex(x => x.id === routeInfo.id);
const tabIndex = tabArray.findIndex((x) => x.id === routeInfo.id);
if (tabIndex > -1) {
tabArray.splice(tabIndex, 1, routeInfo);
} else {
@ -36,7 +38,7 @@ export const createLocationHistory = () => {
} else if (routeInfo.tab) {
tabsHistory[routeInfo.tab] = [routeInfo];
}
}
};
const pop = (routeInfo: RouteInfo) => {
const tabHistory = getTabsHistory(routeInfo.tab);
@ -61,19 +63,22 @@ export const createLocationHistory = () => {
// Replace with updated route
locationHistory.pop();
locationHistory.push(routeInfo);
}
};
const addRoute = (routeInfo: RouteInfo) => {
const tabHistory = getTabsHistory(routeInfo.tab);
if (tabHistory) {
// If the latest routeInfo is the same (going back and forth between tabs), replace it
if (tabHistory[tabHistory.length - 1] && tabHistory[tabHistory.length - 1].id === routeInfo.id) {
if (
tabHistory[tabHistory.length - 1] &&
tabHistory[tabHistory.length - 1].id === routeInfo.id
) {
tabHistory.pop();
}
tabHistory.push(routeInfo);
}
locationHistory.push(routeInfo);
}
};
/**
* Wipes the location history arrays.
@ -90,17 +95,21 @@ export const createLocationHistory = () => {
* then there will not be any route index in
* tabs either.
*/
const existingRouteIndex = locationHistory.findIndex(r => r.position === position);
const existingRouteIndex = locationHistory.findIndex(
(r) => r.position === position
);
if (existingRouteIndex === -1) return;
locationHistory.splice(existingRouteIndex);
const clearTabHistory = (tab: string) => {
const existingTabRouteIndex = tabsHistory[tab].findIndex(r => r.position === position);
const existingTabRouteIndex = tabsHistory[tab].findIndex(
(r) => r.position === position
);
if (existingTabRouteIndex === -1) return;
tabsHistory[tab].splice(existingTabRouteIndex);
}
};
/**
* We also need to search the current tab
@ -112,19 +121,19 @@ export const createLocationHistory = () => {
const tabHistory = tabsHistory[tab];
if (tab && tabHistory) {
clearTabHistory(tab);
/**
* If we are not clearing items after
* a tabs page, it is still possible
* that there are future tabs pages to clear.
* As a result, we need to search through
* all the tab stacks and remove views that appear
* after the given routeInfo.
*
* Example: /non-tabs-page --> /tabs/tab1 --> /non-tabs-page
* (via router.go(-1)) --> /tabs/tab2. The /tabs/tab1 history
* has been overwritten with /tabs/tab2. As a result,
* the /tabs/tab1 route info in the Tab 1 stack should be removed.
*/
/**
* If we are not clearing items after
* a tabs page, it is still possible
* that there are future tabs pages to clear.
* As a result, we need to search through
* all the tab stacks and remove views that appear
* after the given routeInfo.
*
* Example: /non-tabs-page --> /tabs/tab1 --> /non-tabs-page
* (via router.go(-1)) --> /tabs/tab2. The /tabs/tab1 history
* has been overwritten with /tabs/tab2. As a result,
* the /tabs/tab1 route info in the Tab 1 stack should be removed.
*/
} else {
for (const tab in tabsHistory) {
clearTabHistory(tab);
@ -137,7 +146,7 @@ export const createLocationHistory = () => {
locationHistory.length = 0;
}
}
};
const getTabsHistory = (tab: string): RouteInfo[] => {
let history;
if (tab) {
@ -148,7 +157,7 @@ export const createLocationHistory = () => {
}
return history;
}
};
const size = () => locationHistory.length;
@ -166,7 +175,7 @@ export const createLocationHistory = () => {
*/
const index = currentHistory - initialHistory;
return locationHistory[index] || last();
}
};
const last = () => locationHistory[locationHistory.length - 1];
/**
@ -177,9 +186,13 @@ export const createLocationHistory = () => {
* the length of locationHistory, but that only worked since we were pruning
* the array.
*/
const canGoBack = (deep: number = 1, initialHistory: number, currentHistory: number) => {
const canGoBack = (
deep = 1,
initialHistory: number,
currentHistory: number
) => {
return currentHistory - deep >= initialHistory;
}
};
const getFirstRouteInfoForTab = (tab: string): RouteInfo | undefined => {
const tabHistory = getTabsHistory(tab);
@ -187,7 +200,7 @@ export const createLocationHistory = () => {
return tabHistory[0];
}
return undefined;
}
};
const getCurrentRouteInfoForTab = (tab: string): RouteInfo | undefined => {
const tabHistory = getTabsHistory(tab);
@ -195,7 +208,7 @@ export const createLocationHistory = () => {
return tabHistory[tabHistory.length - 1];
}
return undefined;
}
};
/**
* Finds and returns the previous view based upon
@ -207,7 +220,10 @@ export const createLocationHistory = () => {
* do not modify the locationHistory stack so we would
* not update pushedByRoute anyways.
*/
const findLastLocation = (routeInfo: RouteInfo, delta: number = -1): RouteInfo | undefined => {
const findLastLocation = (
routeInfo: RouteInfo,
delta = -1
): RouteInfo | undefined => {
const routeInfos = getTabsHistory(routeInfo.tab);
if (routeInfos) {
if (delta < -1) {
@ -236,7 +252,7 @@ export const createLocationHistory = () => {
}
}
return undefined;
}
};
return {
current,
@ -248,6 +264,6 @@ export const createLocationHistory = () => {
getFirstRouteInfoForTab,
getCurrentRouteInfoForTab,
findLastLocation,
clearHistory
}
}
clearHistory,
};
};

View File

@ -1,27 +1,35 @@
import {
parseQuery,
import type { AnimationBuilder } from "@ionic/vue";
import type {
Router,
RouteLocationNormalized,
NavigationFailure,
RouteLocationRaw
} from 'vue-router';
import { createLocationHistory } from './locationHistory';
import { generateId } from './utils';
import {
RouteLocationRaw,
} from "vue-router";
import { parseQuery } from "vue-router";
import { createLocationHistory } from "./locationHistory";
import type {
ExternalNavigationOptions,
RouteInfo,
RouteParams,
RouteAction,
RouteDirection,
IonicVueRouterOptions,
NavigationInformation
} from './types';
import { AnimationBuilder } from '@ionic/vue';
NavigationInformation,
} from "./types";
import { generateId } from "./utils";
// TODO(FW-2969): types
export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => {
let currentNavigationInfo: NavigationInformation = { direction: undefined, action: undefined, delta: undefined };
export const createIonRouter = (
opts: IonicVueRouterOptions,
router: Router
) => {
let currentNavigationInfo: NavigationInformation = {
direction: undefined,
action: undefined,
delta: undefined,
};
/**
* Ionic Vue should only react to navigation
@ -32,27 +40,37 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
* which is fired once navigation is confirmed
* and any user guards have run.
*/
router.afterEach((to: RouteLocationNormalized, _: RouteLocationNormalized, failure?: NavigationFailure) => {
if (failure) return;
router.afterEach(
(
to: RouteLocationNormalized,
_: RouteLocationNormalized,
failure?: NavigationFailure
) => {
if (failure) return;
const { direction, action, delta } = currentNavigationInfo;
const { direction, action, delta } = currentNavigationInfo;
/**
* When calling router.replace, we are not informed
* about the replace action in opts.history.listen
* but we can check to see if the latest routing action
* was a replace action by looking at the history state.
* We need to use opts.history rather than window.history
* because window.history will be undefined when using SSR.
*/
/**
* When calling router.replace, we are not informed
* about the replace action in opts.history.listen
* but we can check to see if the latest routing action
* was a replace action by looking at the history state.
* We need to use opts.history rather than window.history
* because window.history will be undefined when using SSR.
*/
currentHistoryPosition = opts.history.state.position as number;
currentHistoryPosition = opts.history.state.position as number;
const replaceAction = opts.history.state.replaced ? 'replace' : undefined;
handleHistoryChange(to, action || replaceAction, direction, delta);
const replaceAction = opts.history.state.replaced ? "replace" : undefined;
handleHistoryChange(to, action || replaceAction, direction, delta);
currentNavigationInfo = { direction: undefined, action: undefined, delta: undefined };
});
currentNavigationInfo = {
direction: undefined,
action: undefined,
delta: undefined,
};
}
);
const locationHistory = createLocationHistory();
@ -68,15 +86,15 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
let currentRouteInfo: RouteInfo;
let incomingRouteParams: RouteParams;
let historyChangeListeners: any[] = [];
const historyChangeListeners: any[] = [];
if (typeof (document as any) !== 'undefined') {
document.addEventListener('ionBackButton', (ev: Event) => {
if (typeof (document as any) !== "undefined") {
document.addEventListener("ionBackButton", (ev: Event) => {
(ev as any).detail.register(0, (processNextHandler: () => void) => {
opts.history.go(-1);
processNextHandler();
});
})
});
}
opts.history.listen((_: any, _x: any, info: any) => {
@ -99,38 +117,46 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
* are considered "pop" actions, but when going forward
* we want to make sure the forward animation is used.
*/
action: (info.type === 'pop' && info.delta >= 1) ? 'push' : info.type,
direction: info.direction === '' ? 'forward' : info.direction
action: info.type === "pop" && info.delta >= 1 ? "push" : info.type,
direction: info.direction === "" ? "forward" : info.direction,
};
});
const handleNavigateBack = (defaultHref?: string, routerAnimation?: AnimationBuilder) => {
const routeInfo = locationHistory.current(initialHistoryPosition, currentHistoryPosition);
const handleNavigateBack = (
defaultHref?: string,
routerAnimation?: AnimationBuilder
) => {
const routeInfo = locationHistory.current(
initialHistoryPosition,
currentHistoryPosition
);
if (routeInfo && routeInfo.pushedByRoute) {
const prevInfo = locationHistory.findLastLocation(routeInfo);
if (prevInfo) {
incomingRouteParams = { ...prevInfo, routerAction: 'pop', routerDirection: 'back', routerAnimation: routerAnimation || routeInfo.routerAnimation };
incomingRouteParams = {
...prevInfo,
routerAction: "pop",
routerDirection: "back",
routerAnimation: routerAnimation || routeInfo.routerAnimation,
};
if (
routeInfo.lastPathname === routeInfo.pushedByRoute ||
(
/**
* We need to exclude tab switches/tab
* context changes here because tabbed
* navigation is not linear, but router.back()
* will go back in a linear fashion.
*/
prevInfo.pathname === routeInfo.pushedByRoute &&
/**
* We need to exclude tab switches/tab
* context changes here because tabbed
* navigation is not linear, but router.back()
* will go back in a linear fashion.
*/
(prevInfo.pathname === routeInfo.pushedByRoute &&
/**
* Tab info can be undefined or '' (empty string)
* both are false-y values, so we can just use !.
*/
!routeInfo.tab && !prevInfo.tab
)
!routeInfo.tab &&
!prevInfo.tab)
) {
router.back();
} else {
/**
* When going back to a child page of a tab
* after being on another tab, we need to use
@ -160,22 +186,28 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
router.go(prevInfo.position - routeInfo.position);
}
} else {
handleNavigate(defaultHref, 'pop', 'back');
handleNavigate(defaultHref, "pop", "back");
}
} else {
handleNavigate(defaultHref, 'pop', 'back');
handleNavigate(defaultHref, "pop", "back");
}
}
};
const handleNavigate = (path: RouteLocationRaw, routerAction?: RouteAction, routerDirection?: RouteDirection, routerAnimation?: AnimationBuilder, tab?: string) => {
const handleNavigate = (
path: RouteLocationRaw,
routerAction?: RouteAction,
routerDirection?: RouteDirection,
routerAnimation?: AnimationBuilder,
tab?: string
) => {
setIncomingRouteParams(routerAction, routerDirection, routerAnimation, tab);
if (routerAction === 'push') {
if (routerAction === "push") {
router.push(path);
} else {
router.replace(path);
}
}
};
// TODO RouteLocationNormalized
const handleHistoryChange = (
@ -186,17 +218,22 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
) => {
let leavingLocationInfo: RouteInfo;
if (incomingRouteParams) {
/**
* If we are replacing the state of a route
* with another route, the "leaving" route
* is at the same position in location history
* as where the replaced route will exist.
*/
if (incomingRouteParams.routerAction === 'replace') {
leavingLocationInfo = locationHistory.current(initialHistoryPosition, currentHistoryPosition);
} else if (incomingRouteParams.routerAction === 'pop') {
leavingLocationInfo = locationHistory.current(initialHistoryPosition, currentHistoryPosition + 1);
if (incomingRouteParams.routerAction === "replace") {
leavingLocationInfo = locationHistory.current(
initialHistoryPosition,
currentHistoryPosition
);
} else if (incomingRouteParams.routerAction === "pop") {
leavingLocationInfo = locationHistory.current(
initialHistoryPosition,
currentHistoryPosition + 1
);
/**
* If the Ionic Router action was "pop"
@ -233,7 +270,7 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
* the past history and you can no longer go
* forward to /page2 or /page3.
*/
if (action === 'replace') {
if (action === "replace") {
locationHistory.clearHistory();
}
} else {
@ -249,8 +286,14 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
* so we can grab the previous item in history relative
* to where the history state currently is.
*/
const position = (incomingRouteParams.routerDirection === 'root') ? currentHistoryPosition : currentHistoryPosition - 1;
leavingLocationInfo = locationHistory.current(initialHistoryPosition, position);
const position =
incomingRouteParams.routerDirection === "root"
? currentHistoryPosition
: currentHistoryPosition - 1;
leavingLocationInfo = locationHistory.current(
initialHistoryPosition,
position
);
}
} else {
leavingLocationInfo = currentRouteInfo;
@ -258,42 +301,49 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
if (!leavingLocationInfo) {
leavingLocationInfo = {
pathname: '',
search: ''
}
pathname: "",
search: "",
};
}
const leavingUrl = leavingLocationInfo.pathname + leavingLocationInfo.search;
const leavingUrl =
leavingLocationInfo.pathname + leavingLocationInfo.search;
if (leavingUrl !== location.fullPath) {
if (!incomingRouteParams) {
if (action === 'replace') {
if (action === "replace") {
incomingRouteParams = {
routerAction: 'replace',
routerDirection: 'none'
}
} else if (action === 'pop') {
const routeInfo = locationHistory.current(initialHistoryPosition, currentHistoryPosition - delta);
routerAction: "replace",
routerDirection: "none",
};
} else if (action === "pop") {
const routeInfo = locationHistory.current(
initialHistoryPosition,
currentHistoryPosition - delta
);
if (routeInfo && routeInfo.pushedByRoute) {
const prevRouteInfo = locationHistory.findLastLocation(routeInfo, delta);
const prevRouteInfo = locationHistory.findLastLocation(
routeInfo,
delta
);
incomingRouteParams = {
...prevRouteInfo,
routerAction: 'pop',
routerDirection: 'back'
routerAction: "pop",
routerDirection: "back",
};
} else {
incomingRouteParams = {
routerAction: 'pop',
routerDirection: 'none'
}
routerAction: "pop",
routerDirection: "none",
};
}
}
if (!incomingRouteParams) {
incomingRouteParams = {
routerAction: 'push',
routerDirection: direction || 'forward'
}
routerAction: "push",
routerDirection: direction || "forward",
};
}
}
@ -301,31 +351,39 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
if (incomingRouteParams?.id) {
routeInfo = {
...incomingRouteParams,
lastPathname: leavingLocationInfo.pathname
}
lastPathname: leavingLocationInfo.pathname,
};
} else {
const isPushed = incomingRouteParams.routerAction === 'push' && incomingRouteParams.routerDirection === 'forward';
const isPushed =
incomingRouteParams.routerAction === "push" &&
incomingRouteParams.routerDirection === "forward";
routeInfo = {
id: generateId('routeInfo'),
id: generateId("routeInfo"),
...incomingRouteParams,
lastPathname: leavingLocationInfo.pathname,
pathname: location.path,
search: location.fullPath && location.fullPath.split('?')[1] || '',
search: (location.fullPath && location.fullPath.split("?")[1]) || "",
params: location.params && location.params,
prevRouteLastPathname: leavingLocationInfo.lastPathname
}
prevRouteLastPathname: leavingLocationInfo.lastPathname,
};
if (isPushed) {
routeInfo.pushedByRoute = (leavingLocationInfo.pathname !== '') ? leavingLocationInfo.pathname : undefined;
} else if (routeInfo.routerAction === 'pop') {
routeInfo.pushedByRoute =
leavingLocationInfo.pathname !== ""
? leavingLocationInfo.pathname
: undefined;
} else if (routeInfo.routerAction === "pop") {
const route = locationHistory.findLastLocation(routeInfo);
routeInfo.pushedByRoute = route?.pushedByRoute;
} else if (routeInfo.routerAction === 'push' && routeInfo.tab !== leavingLocationInfo.tab) {
const lastRoute = locationHistory.getCurrentRouteInfoForTab(routeInfo.tab);
} else if (
routeInfo.routerAction === "push" &&
routeInfo.tab !== leavingLocationInfo.tab
) {
const lastRoute = locationHistory.getCurrentRouteInfoForTab(
routeInfo.tab
);
routeInfo.pushedByRoute = lastRoute?.pushedByRoute;
} else if (routeInfo.routerAction === 'replace') {
} else if (routeInfo.routerAction === "replace") {
/**
* When replacing a route, we want to make sure we select the current route
* that we are on, not the last route in the stack. The last route in the stack
@ -337,7 +395,10 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
* be replaced with /page3 even though /page2 is the last
* item in the stack/
*/
const currentRouteInfo = locationHistory.current(initialHistoryPosition, currentHistoryPosition);
const currentRouteInfo = locationHistory.current(
initialHistoryPosition,
currentHistoryPosition
);
/**
* If going from /home to /child, then replacing from
@ -345,15 +406,21 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
* say that /home was pushed by /home which is not correct.
*/
const currentPushedBy = currentRouteInfo?.pushedByRoute;
const pushedByRoute = (currentPushedBy !== undefined && currentPushedBy !== routeInfo.pathname) ? currentPushedBy : routeInfo.pushedByRoute;
const pushedByRoute =
currentPushedBy !== undefined &&
currentPushedBy !== routeInfo.pathname
? currentPushedBy
: routeInfo.pushedByRoute;
routeInfo.lastPathname = currentRouteInfo?.pathname || routeInfo.lastPathname;
routeInfo.lastPathname =
currentRouteInfo?.pathname || routeInfo.lastPathname;
routeInfo.pushedByRoute = pushedByRoute;
routeInfo.routerDirection = currentRouteInfo?.routerDirection || routeInfo.routerDirection;
routeInfo.routerAnimation = currentRouteInfo?.routerAnimation || routeInfo.routerAnimation;
routeInfo.routerDirection =
currentRouteInfo?.routerDirection || routeInfo.routerDirection;
routeInfo.routerAnimation =
currentRouteInfo?.routerAnimation || routeInfo.routerAnimation;
routeInfo.prevRouteLastPathname = currentRouteInfo?.lastPathname;
}
}
routeInfo.position = currentHistoryPosition;
@ -379,7 +446,8 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
* we want to make sure we exclude that
* action by ensuring historySize > 0.
*/
const isReplacing = historySize === historyDiff && historySize > 0 && action === 'replace';
const isReplacing =
historySize === historyDiff && historySize > 0 && action === "replace";
if (historySize > historyDiff || isReplacing) {
/**
* When navigating back through the history,
@ -400,7 +468,8 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
*/
if (
(routeInfo.routerAction === 'push' || routeInfo.routerAction === 'replace') &&
(routeInfo.routerAction === "push" ||
routeInfo.routerAction === "replace") &&
delta === undefined
) {
locationHistory.clearHistory(routeInfo);
@ -422,20 +491,25 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
currentRouteInfo = routeInfo;
}
incomingRouteParams = undefined;
historyChangeListeners.forEach(cb => cb(currentRouteInfo));
}
historyChangeListeners.forEach((cb) => cb(currentRouteInfo));
};
const getCurrentRouteInfo = () => currentRouteInfo;
const canGoBack = (deep: number = 1) => locationHistory.canGoBack(deep, initialHistoryPosition, currentHistoryPosition);
const canGoBack = (deep = 1) =>
locationHistory.canGoBack(
deep,
initialHistoryPosition,
currentHistoryPosition
);
const navigate = (navigationOptions: ExternalNavigationOptions) => {
const { routerAnimation, routerDirection, routerLink } = navigationOptions;
setIncomingRouteParams('push', routerDirection, routerAnimation);
setIncomingRouteParams("push", routerDirection, routerAnimation);
router.push(routerLink);
}
};
const resetTab = (tab: string) => {
/**
@ -454,21 +528,21 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
if (routeInfo) {
router.go(routeInfo.position - currentHistoryPosition);
}
}
};
const changeTab = (tab: string, path?: string) => {
if (!path) return;
const routeInfo = locationHistory.getCurrentRouteInfoForTab(tab);
const [pathname] = path.split('?');
const [pathname] = path.split("?");
if (routeInfo) {
incomingRouteParams = {
...incomingRouteParams,
routerAction: 'push',
routerDirection: 'none',
tab
}
routerAction: "push",
routerDirection: "none",
tab,
};
/**
* When going back to a tab
@ -478,15 +552,17 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
* tab you are on.
*/
if (routeInfo.pathname === pathname) {
router.push({ path: routeInfo.pathname, query: parseQuery(routeInfo.search) });
router.push({
path: routeInfo.pathname,
query: parseQuery(routeInfo.search),
});
} else {
router.push({ path: pathname, query: parseQuery(routeInfo.search) });
}
} else {
handleNavigate(pathname, "push", "none", undefined, tab);
}
else {
handleNavigate(pathname, 'push', 'none', undefined, tab);
}
}
};
/**
* This method is invoked by the IonTabs component
@ -506,7 +582,12 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
* in the locationHistory stack. As a result,
* we cannot use locationHistory.last() here.
*/
const ri = { ...locationHistory.current(initialHistoryPosition, currentHistoryPosition) };
const ri = {
...locationHistory.current(
initialHistoryPosition,
currentHistoryPosition
),
};
/**
* handleHistoryChange is tabs-agnostic by design.
@ -559,34 +640,42 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
ri.pushedByRoute = undefined;
locationHistory.update(ri);
}
}
};
const registerHistoryChangeListener = (cb: any) => {
historyChangeListeners.push(cb);
}
};
const setIncomingRouteParams = (routerAction: RouteAction = 'push', routerDirection: RouteDirection = 'forward', routerAnimation?: AnimationBuilder, tab?: string) => {
const setIncomingRouteParams = (
routerAction: RouteAction = "push",
routerDirection: RouteDirection = "forward",
routerAnimation?: AnimationBuilder,
tab?: string
) => {
incomingRouteParams = {
routerAction,
routerDirection,
routerAnimation,
tab
tab,
};
}
};
const goBack = (routerAnimation?: AnimationBuilder) => {
setIncomingRouteParams('pop', 'back', routerAnimation);
router.back()
setIncomingRouteParams("pop", "back", routerAnimation);
router.back();
};
const goForward = (routerAnimation?: AnimationBuilder) => {
setIncomingRouteParams('push', 'forward', routerAnimation);
setIncomingRouteParams("push", "forward", routerAnimation);
router.forward();
}
};
const getLeavingRouteInfo = () => {
return locationHistory.current(initialHistoryPosition, currentHistoryPosition);
}
return locationHistory.current(
initialHistoryPosition,
currentHistoryPosition
);
};
return {
handleNavigate,
@ -600,6 +689,6 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
changeTab,
registerHistoryChangeListener,
goBack,
goForward
}
}
goForward,
};
};

View File

@ -1,6 +1,6 @@
import { AnimationBuilder } from '@ionic/vue';
import { RouteLocationMatched, RouterOptions } from 'vue-router';
import { Ref } from 'vue';
import type { AnimationBuilder } from "@ionic/vue";
import type { Ref } from "vue";
import type { RouteLocationMatched, RouterOptions } from "vue-router";
// TODO(FW-2969): types
@ -56,8 +56,8 @@ export interface RouteParams {
id?: string;
}
export type RouteAction = 'push' | 'pop' | 'replace';
export type RouteDirection = 'forward' | 'back' | 'root' | 'none';
export type RouteAction = "push" | "pop" | "replace";
export type RouteDirection = "forward" | "back" | "root" | "none";
export interface ViewItem {
id: string;

View File

@ -1,7 +1,7 @@
const ids: { [k: string]: number } = { main: 0 };
export const generateId = (type = 'main') => {
export const generateId = (type = "main") => {
const id = (ids[type] ?? 0) + 1;
ids[type] = id;
return (id).toString();
return id.toString();
};

View File

@ -1,13 +1,11 @@
import { generateId } from './utils';
import { RouteInfo,
ViewItem,
ViewStacks,
} from './types';
import { RouteLocationMatched, Router } from 'vue-router';
import { shallowRef } from 'vue';
import { shallowRef } from "vue";
import type { RouteLocationMatched, Router } from "vue-router";
import type { RouteInfo, ViewItem, ViewStacks } from "./types";
import { generateId } from "./utils";
export const createViewStacks = (router: Router) => {
let viewStacks: ViewStacks = {};
const viewStacks: ViewStacks = {};
/**
* Returns the number of active stacks.
@ -20,11 +18,11 @@ export const createViewStacks = (router: Router) => {
const clear = (outletId: number) => {
delete viewStacks[outletId];
}
};
const getViewStack = (outletId: number) => {
return viewStacks[outletId];
}
};
const registerIonPage = (viewItem: ViewItem, ionPage: HTMLElement) => {
viewItem.ionPageElement = ionPage;
@ -36,45 +34,57 @@ export const createViewStacks = (router: Router) => {
* and will not run route guards that
* are written in the component.
*/
viewItem.matchedRoute.instances = { default: viewItem.vueComponentRef.value };
}
viewItem.matchedRoute.instances = {
default: viewItem.vueComponentRef.value,
};
};
const findViewItemByRouteInfo = (routeInfo: RouteInfo, outletId?: number) => {
return findViewItemByPath(routeInfo.pathname, outletId, false);
}
};
const findLeavingViewItemByRouteInfo = (routeInfo: RouteInfo, outletId?: number, mustBeIonRoute: boolean = true) => {
const findLeavingViewItemByRouteInfo = (
routeInfo: RouteInfo,
outletId?: number,
mustBeIonRoute = true
) => {
return findViewItemByPath(routeInfo.lastPathname, outletId, mustBeIonRoute);
}
};
const findViewItemByPathname = (pathname: string, outletId?: number) => {
return findViewItemByPath(pathname, outletId, false);
}
};
const findViewItemInStack = (path: string, stack: ViewItem[]): ViewItem | undefined => {
const findViewItemInStack = (
path: string,
stack: ViewItem[]
): ViewItem | undefined => {
return stack.find((viewItem: ViewItem) => {
if (viewItem.pathname === path) {
return viewItem;
}
return undefined;
})
}
});
};
const findViewItemByPath = (path: string, outletId?: number, mustBeIonRoute: boolean = false): ViewItem | undefined => {
const findViewItemByPath = (
path: string,
outletId?: number,
mustBeIonRoute = false
): ViewItem | undefined => {
const matchView = (viewItem: ViewItem) => {
if (
(mustBeIonRoute && !viewItem.ionRoute) ||
path === ''
) {
if ((mustBeIonRoute && !viewItem.ionRoute) || path === "") {
return false;
}
const resolvedPath = router.resolve(path);
const findMatchedRoute = resolvedPath.matched.find((matchedRoute: RouteLocationMatched) => matchedRoute === viewItem.matchedRoute);
const findMatchedRoute = resolvedPath.matched.find(
(matchedRoute: RouteLocationMatched) =>
matchedRoute === viewItem.matchedRoute
);
if (findMatchedRoute) {
/**
* /page/1 and /page/2 should not match
* to the same view item otherwise there will
@ -83,7 +93,7 @@ export const createViewStacks = (router: Router) => {
* so the page 2 params are properly passed
* to the developer's app.
*/
const hasParameter = findMatchedRoute.path.includes(':');
const hasParameter = findMatchedRoute.path.includes(":");
if (hasParameter && path !== viewItem.pathname) {
return false;
}
@ -92,31 +102,39 @@ export const createViewStacks = (router: Router) => {
}
return undefined;
}
};
if (outletId) {
const stack = viewStacks[outletId];
if (!stack) return undefined;
const match = (router) ? stack.find(matchView) : findViewItemInStack(path, stack)
const match = router
? stack.find(matchView)
: findViewItemInStack(path, stack);
if (match) return match;
} else {
for (let outletId in viewStacks) {
for (const outletId in viewStacks) {
const stack = viewStacks[outletId];
const viewItem = findViewItemInStack(path, stack);
if (viewItem) {
return viewItem;
return viewItem;
}
}
}
return undefined;
}
};
// TODO(FW-2969): type
const createViewItem = (outletId: number, vueComponent: any, matchedRoute: RouteLocationMatched, routeInfo: RouteInfo, ionPage?: HTMLElement): ViewItem => {
const createViewItem = (
outletId: number,
vueComponent: any,
matchedRoute: RouteLocationMatched,
routeInfo: RouteInfo,
ionPage?: HTMLElement
): ViewItem => {
return {
id: generateId('viewItem'),
id: generateId("viewItem"),
pathname: routeInfo.pathname,
outletId,
matchedRoute,
@ -127,9 +145,9 @@ export const createViewStacks = (router: Router) => {
mount: false,
exact: routeInfo.pathname === matchedRoute.path,
params: routeInfo.params,
vueComponentData: {}
vueComponentData: {},
};
}
};
const add = (viewItem: ViewItem): void => {
const { outletId } = viewItem;
@ -138,25 +156,29 @@ export const createViewStacks = (router: Router) => {
} else {
viewStacks[outletId].push(viewItem);
}
}
};
const remove = (viewItem: ViewItem, outletId?: number): void => {
if (!outletId) { throw Error('outletId required') }
if (!outletId) {
throw Error("outletId required");
}
const viewStack = viewStacks[outletId];
if (viewStack) {
viewStacks[outletId] = viewStack.filter(item => item.id !== viewItem.id);
viewStacks[outletId] = viewStack.filter(
(item) => item.id !== viewItem.id
);
}
}
};
const getChildrenToRender = (outletId: number): ViewItem[] => {
const viewStack = viewStacks[outletId];
if (viewStack) {
const components = viewStacks[outletId].filter(v => v.mount);
const components = viewStacks[outletId].filter((v) => v.mount);
return components;
}
return [];
}
};
/**
* When navigating backwards, we need to clean up and
@ -165,11 +187,15 @@ export const createViewStacks = (router: Router) => {
* important when using router.go and stepping back
* multiple pages at a time.
*/
const unmountLeavingViews = (outletId: number, viewItem: ViewItem, delta: number = 1) => {
const unmountLeavingViews = (
outletId: number,
viewItem: ViewItem,
delta = 1
) => {
const viewStack = viewStacks[outletId];
if (!viewStack) return;
const startIndex = viewStack.findIndex(v => v === viewItem);
const startIndex = viewStack.findIndex((v) => v === viewItem);
for (let i = startIndex + 1; i < startIndex - delta; i++) {
const viewItem = viewStack[i];
@ -178,7 +204,7 @@ export const createViewStacks = (router: Router) => {
viewItem.ionRoute = false;
viewItem.matchedRoute.instances = {};
}
}
};
/**
* When navigating forward it is possible for
@ -198,16 +224,20 @@ export const createViewStacks = (router: Router) => {
* to go back to /page2 and /home, so we need both pages mounted
* in the DOM.
*/
const mountIntermediaryViews = (outletId: number, viewItem: ViewItem, delta: number = 1) => {
const mountIntermediaryViews = (
outletId: number,
viewItem: ViewItem,
delta = 1
) => {
const viewStack = viewStacks[outletId];
if (!viewStack) return;
const startIndex = viewStack.findIndex(v => v === viewItem);
const startIndex = viewStack.findIndex((v) => v === viewItem);
for (let i = startIndex + 1; i < startIndex + delta; i++) {
viewStack[i].mount = true;
}
}
};
return {
unmountLeavingViews,
@ -222,6 +252,6 @@ export const createViewStacks = (router: Router) => {
remove,
registerIonPage,
getViewStack,
size
}
}
size,
};
};