Henning Dieterichs 2 年之前
父节点
当前提交
008c3074d0
共有 1 个文件被更改,包括 85 次插入3 次删除
  1. 85 3
      website/src/website/pages/DocsPage.tsx

+ 85 - 3
website/src/website/pages/DocsPage.tsx

@@ -1,7 +1,88 @@
-import React = require("react");
+import { observable } from "mobx";
 import { Page } from "../components/Page";
+import {
+	HistoryController,
+	IHistoryModel,
+	ILocation,
+} from "../utils/ObservableHistory";
+import React = require("react");
+
+export class DocsPage extends React.Component implements IHistoryModel {
+	private _lastIFrame: HTMLIFrameElement | null = null;
+
+	private readonly setIFrame = (iframe: HTMLIFrameElement | null) => {
+		if (iframe === this._lastIFrame) {
+			return;
+		}
+		if (this._lastIFrame) {
+			this._lastIFrame.contentWindow?.removeEventListener(
+				"hashchange",
+				this.onIFrameLoad
+			);
+			this._lastIFrame.removeEventListener("load", this.onIFrameLoad);
+		}
+		if (iframe) {
+			iframe.addEventListener("load", this.onIFrameLoad);
+		}
+		this._lastIFrame = iframe;
+	};
+
+	private readonly onIFrameLoad = () => {
+		this._lastIFrame!.contentWindow?.addEventListener("hashchange", () =>
+			this.updateLocationFromIFrame()
+		);
+		this.updateLocationFromIFrame();
+	};
+
+	private updateLocationFromIFrame(): void {
+		const match =
+			this._lastIFrame?.contentWindow!.location.href.match(
+				/typedoc\/(.*)/
+			);
+		if (match) {
+			let hashValue = match[1];
+			if (hashValue === "index.html") {
+				hashValue = "";
+			}
+			this.location = { hashValue, searchParams: {} };
+		}
+	}
+
+	@observable.ref
+	location!: ILocation;
+	historyId: number = 0;
+
+	getTypedocUrl(): string {
+		let hashValue = this.location?.hashValue ?? "";
+		// make sure hashValue is a valid path
+		if (
+			!hashValue.match(/^[a-zA-Z0-9#\._\-\/]*$/) ||
+			hashValue.indexOf("..") !== -1
+		) {
+			hashValue = "";
+		}
+
+		return `./typedoc/${hashValue}`;
+	}
+
+	updateLocation(newLocation: ILocation): void {
+		this.location = newLocation;
+
+		if (this._lastIFrame) {
+			this._lastIFrame.src = this.getTypedocUrl();
+		}
+	}
+
+	constructor(props: any) {
+		super(props);
+
+		new HistoryController((location) => {
+			this.location = location;
+			return this;
+		});
+	}
 
-export class DocsPage extends React.Component {
+	// not reactive to prevent unnecessary reloads of the iframe
 	render() {
 		if (!localStorage.getItem("tsd-theme")) {
 			// Set default theme to light, unfortunately there is no config option for this
@@ -11,9 +92,10 @@ export class DocsPage extends React.Component {
 		return (
 			<Page>
 				<iframe
+					ref={this.setIFrame}
 					className="full-iframe"
 					frameBorder={0}
-					src="./typedoc/"
+					src={this.getTypedocUrl()}
 				/>
 			</Page>
 		);