Convert URLRouter.js to typescript

This commit is contained in:
RMidhunSuresh 2022-02-22 13:14:27 +05:30
parent d9bfca10e1
commit 4c3e0a6ff0
3 changed files with 44 additions and 28 deletions

View file

@ -19,6 +19,8 @@ import {BaseObservableValue, ObservableValue} from "../../observable/ObservableV
type AllowsChild<T> = (parent: Segment<T> | undefined, child: Segment<T>) => boolean; type AllowsChild<T> = (parent: Segment<T> | undefined, child: Segment<T>) => boolean;
export type OptionalValue<T> = T extends true? [(undefined | true)?]: [T];
export class Navigation<T> { export class Navigation<T> {
private readonly _allowsChild: AllowsChild<T>; private readonly _allowsChild: AllowsChild<T>;
private _path: Path<T>; private _path: Path<T>;

View file

@ -14,19 +14,33 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
export class URLRouter { import type {History} from "../../platform/web/dom/History.js";
constructor({history, navigation, parseUrlPath, stringifyPath}) { import type {Navigation, Segment, Path, OptionalValue} from "./Navigation";
import type {SubscriptionHandle} from "../../observable/BaseObservable";
import type {SegmentType} from "./index";
type ParseURLPath<T> = (urlPath: string, currentNavPath: Path<T>, defaultSessionId: string | null) => Segment<T>[];
type StringifyPath<T> = (path: Path<T>) => string;
export class URLRouter<T extends SegmentType> {
private readonly _history: History;
private readonly _navigation: Navigation<T>;
private readonly _parseUrlPath: ParseURLPath<T>;
private readonly _stringifyPath: StringifyPath<T>;
private _subscription?: SubscriptionHandle;
private _pathSubscription?: SubscriptionHandle;
private _isApplyingUrl: boolean = false;
private _defaultSessionId: string | null;
constructor(history: History, navigation: Navigation<T>, parseUrlPath: ParseURLPath<T>, stringifyPath: StringifyPath<T>) {
this._history = history; this._history = history;
this._navigation = navigation; this._navigation = navigation;
this._parseUrlPath = parseUrlPath; this._parseUrlPath = parseUrlPath;
this._stringifyPath = stringifyPath; this._stringifyPath = stringifyPath;
this._subscription = null;
this._pathSubscription = null;
this._isApplyingUrl = false;
this._defaultSessionId = this._getLastSessionId(); this._defaultSessionId = this._getLastSessionId();
} }
_getLastSessionId() { _getLastSessionId(): string | null {
const navPath = this._urlAsNavPath(this._history.getLastUrl() || ""); const navPath = this._urlAsNavPath(this._history.getLastUrl() || "");
const sessionId = navPath.get("session")?.value; const sessionId = navPath.get("session")?.value;
if (typeof sessionId === "string") { if (typeof sessionId === "string") {
@ -35,7 +49,7 @@ export class URLRouter {
return null; return null;
} }
attach() { attach(): void {
this._subscription = this._history.subscribe(url => this._applyUrl(url)); this._subscription = this._history.subscribe(url => this._applyUrl(url));
// subscribe to path before applying initial url // subscribe to path before applying initial url
// so redirects in _applyNavPathToHistory are reflected in url bar // so redirects in _applyNavPathToHistory are reflected in url bar
@ -43,12 +57,12 @@ export class URLRouter {
this._applyUrl(this._history.get()); this._applyUrl(this._history.get());
} }
dispose() { dispose(): void {
this._subscription = this._subscription(); if (this._subscription) { this._subscription = this._subscription(); }
this._pathSubscription = this._pathSubscription(); if (this._pathSubscription) { this._pathSubscription = this._pathSubscription(); }
} }
_applyNavPathToHistory(path) { _applyNavPathToHistory(path: Path<T>): void {
const url = this.urlForPath(path); const url = this.urlForPath(path);
if (url !== this._history.get()) { if (url !== this._history.get()) {
if (this._isApplyingUrl) { if (this._isApplyingUrl) {
@ -60,7 +74,7 @@ export class URLRouter {
} }
} }
_applyNavPathToNavigation(navPath) { _applyNavPathToNavigation(navPath: Path<T>): void {
// this will cause _applyNavPathToHistory to be called, // this will cause _applyNavPathToHistory to be called,
// so set a flag whether this request came from ourselves // so set a flag whether this request came from ourselves
// (in which case it is a redirect if the url does not match the current one) // (in which case it is a redirect if the url does not match the current one)
@ -69,21 +83,21 @@ export class URLRouter {
this._isApplyingUrl = false; this._isApplyingUrl = false;
} }
_urlAsNavPath(url) { _urlAsNavPath(url: string): Path<T> {
const urlPath = this._history.urlAsPath(url); const urlPath = this._history.urlAsPath(url);
return this._navigation.pathFrom(this._parseUrlPath(urlPath, this._navigation.path, this._defaultSessionId)); return this._navigation.pathFrom(this._parseUrlPath(urlPath, this._navigation.path, this._defaultSessionId));
} }
_applyUrl(url) { _applyUrl(url: string): void {
const navPath = this._urlAsNavPath(url); const navPath = this._urlAsNavPath(url);
this._applyNavPathToNavigation(navPath); this._applyNavPathToNavigation(navPath);
} }
pushUrl(url) { pushUrl(url: string): void {
this._history.pushUrl(url); this._history.pushUrl(url);
} }
tryRestoreLastUrl() { tryRestoreLastUrl(): boolean {
const lastNavPath = this._urlAsNavPath(this._history.getLastUrl() || ""); const lastNavPath = this._urlAsNavPath(this._history.getLastUrl() || "");
if (lastNavPath.segments.length !== 0) { if (lastNavPath.segments.length !== 0) {
this._applyNavPathToNavigation(lastNavPath); this._applyNavPathToNavigation(lastNavPath);
@ -92,8 +106,8 @@ export class URLRouter {
return false; return false;
} }
urlForSegments(segments) { urlForSegments(segments: Segment<T>[]): string | undefined {
let path = this._navigation.path; let path: Path<T> | null = this._navigation.path;
for (const segment of segments) { for (const segment of segments) {
path = path.with(segment); path = path.with(segment);
if (!path) { if (!path) {
@ -103,29 +117,29 @@ export class URLRouter {
return this.urlForPath(path); return this.urlForPath(path);
} }
urlForSegment(type, value) { urlForSegment<K extends keyof T>(type: K, ...value: OptionalValue<T[K]>): string | undefined {
return this.urlForSegments([this._navigation.segment(type, value)]); return this.urlForSegments([this._navigation.segment(type, ...value)]);
} }
urlUntilSegment(type) { urlUntilSegment(type: keyof T): string {
return this.urlForPath(this._navigation.path.until(type)); return this.urlForPath(this._navigation.path.until(type));
} }
urlForPath(path) { urlForPath(path: Path<T>): string {
return this._history.pathAsUrl(this._stringifyPath(path)); return this._history.pathAsUrl(this._stringifyPath(path));
} }
openRoomActionUrl(roomId) { openRoomActionUrl(roomId: string) {
// not a segment to navigation knowns about, so append it manually // not a segment to navigation knowns about, so append it manually
const urlPath = `${this._stringifyPath(this._navigation.path.until("session"))}/open-room/${roomId}`; const urlPath = `${this._stringifyPath(this._navigation.path.until("session"))}/open-room/${roomId}`;
return this._history.pathAsUrl(urlPath); return this._history.pathAsUrl(urlPath);
} }
createSSOCallbackURL() { createSSOCallbackURL(): string {
return window.location.origin; return window.location.origin;
} }
normalizeUrl() { normalizeUrl(): void {
// Remove any queryParameters from the URL // Remove any queryParameters from the URL
// Gets rid of the loginToken after SSO // Gets rid of the loginToken after SSO
this._history.replaceUrlSilently(`${window.location.origin}/${window.location.hash}`); this._history.replaceUrlSilently(`${window.location.origin}/${window.location.hash}`);

View file

@ -15,10 +15,10 @@ limitations under the License.
*/ */
import {Navigation, Segment} from "./Navigation"; import {Navigation, Segment} from "./Navigation";
import {URLRouter} from "./URLRouter.js"; import {URLRouter} from "./URLRouter";
import type {Path} from "./Navigation"; import type {Path} from "./Navigation";
type SegmentType = { export type SegmentType = {
"login": true; "login": true;
"session": string; "session": string;
"sso": string; "sso": string;
@ -124,7 +124,7 @@ export function addPanelIfNeeded<T extends SegmentType>(navigation: Navigation<T
return _path; return _path;
} }
export function parseUrlPath(urlPath: string, currentNavPath: Path<SegmentType>, defaultSessionId: string): Segment<SegmentType>[] { export function parseUrlPath(urlPath: string, currentNavPath: Path<SegmentType>, defaultSessionId: string | null): Segment<SegmentType>[] {
// substr(1) to take of initial / // substr(1) to take of initial /
const parts = urlPath.substring(1).split("/"); const parts = urlPath.substring(1).split("/");
const iterator = parts[Symbol.iterator](); const iterator = parts[Symbol.iterator]();