jenkins-bot has submitted this change and it was merged. (
https://gerrit.wikimedia.org/r/396418 )
Change subject: Update: browser window / tab title per page
......................................................................
Update: browser window / tab title per page
Bug: T180465
Change-Id: I46bd5ded51df65651045613ea0b588d48f5c1847
---
M docs/development.md
M package.json
M src/client/index.tsx
A src/common/format-doc-title.ts
M src/common/pages/about.tsx
M src/common/pages/error.tsx
M src/common/pages/not-found.tsx
M src/common/pages/style-guide.tsx
M src/common/pages/summary.tsx
M src/common/pages/wiki.tsx
M src/common/router/route.ts
M src/common/router/router.ts
M src/server/components/html-page.tsx
M src/server/index.tsx
M test/server/components/html-page.test.ts
15 files changed, 59 insertions(+), 26 deletions(-)
Approvals:
Jhernandez: Looks good to me, approved
jenkins-bot: Verified
diff --git a/docs/development.md b/docs/development.md
index 9bba644..f4e7366 100644
--- a/docs/development.md
+++ b/docs/development.md
@@ -193,6 +193,7 @@
Marvin uses the following abbreviations:
- Configuration => config
+- Document => doc
- Parameters => params
- Properties => props
- Utilities => utils
diff --git a/package.json b/package.json
index c0e4eb9..ffabbd5 100644
--- a/package.json
+++ b/package.json
@@ -104,7 +104,7 @@
"bundlesize": [
{
"path": "dist/public/index.*.js",
- "maxSize": "3.8KB"
+ "maxSize": "3.9KB"
},
{
"path": "dist/public/runtime.*.js",
diff --git a/src/client/index.tsx b/src/client/index.tsx
index de270a4..72b596d 100644
--- a/src/client/index.tsx
+++ b/src/client/index.tsx
@@ -5,6 +5,7 @@
import { RouteResponse, newRouter } from "../common/router/router";
import { SSRData } from "../common/models/ssr-data";
import { WithContext } from "../common/components/with-context";
+import { formatDocTitle } from "../common/format-doc-title";
import { routes } from "../common/router/routes";
// Include preact/debug only in development for React DevTools integration.
@@ -25,7 +26,10 @@
throw new Error('Missing element with "root" ID.');
})();
-function renderPageRoot({ Component, props }: RouteResponse<any>) {
+function renderPageRoot({ Component, props, title }: RouteResponse<any>) {
+ // Update the window / tab title.
+ document.title = formatDocTitle(title ? title(props) : undefined);
+
render(
<WithContext history={history}>
<Component {...props} />
diff --git a/src/common/format-doc-title.ts b/src/common/format-doc-title.ts
new file mode 100644
index 0000000..8591060
--- /dev/null
+++ b/src/common/format-doc-title.ts
@@ -0,0 +1,3 @@
+export function formatDocTitle(title?: string) {
+ return `${title ? `${title} - ` : ""}Marvin`;
+}
diff --git a/src/common/pages/about.tsx b/src/common/pages/about.tsx
index 24b7440..a95242c 100644
--- a/src/common/pages/about.tsx
+++ b/src/common/pages/about.tsx
@@ -84,5 +84,7 @@
</App>
);
}
- }
+ },
+
+ title: () => "About"
};
diff --git a/src/common/pages/error.tsx b/src/common/pages/error.tsx
index 6c1bbe2..e72dd99 100644
--- a/src/common/pages/error.tsx
+++ b/src/common/pages/error.tsx
@@ -21,5 +21,7 @@
</p>
</Page>
);
- }
+ },
+
+ title: () => "Unexpected error"
};
diff --git a/src/common/pages/not-found.tsx b/src/common/pages/not-found.tsx
index ef7fc98..ce307bb 100644
--- a/src/common/pages/not-found.tsx
+++ b/src/common/pages/not-found.tsx
@@ -21,5 +21,7 @@
</Page>
</App>
);
- }
+ },
+
+ title: () => "Not found"
};
diff --git a/src/common/pages/style-guide.tsx b/src/common/pages/style-guide.tsx
index 089f980..408fca5 100644
--- a/src/common/pages/style-guide.tsx
+++ b/src/common/pages/style-guide.tsx
@@ -60,5 +60,7 @@
</Page>
</App>
);
- }
+ },
+
+ title: () => "Style guide"
};
diff --git a/src/common/pages/summary.tsx b/src/common/pages/summary.tsx
index a579127..229a620 100644
--- a/src/common/pages/summary.tsx
+++ b/src/common/pages/summary.tsx
@@ -68,5 +68,7 @@
</Page>
</App>
);
- }
+ },
+
+ title: ({ summary }: Props) => summary.titleText
};
diff --git a/src/common/pages/wiki.tsx b/src/common/pages/wiki.tsx
index df54723..e854d12 100644
--- a/src/common/pages/wiki.tsx
+++ b/src/common/pages/wiki.tsx
@@ -88,5 +88,7 @@
</Page>
</App>
);
- }
+ },
+
+ title: ({ page }: Props) => page.titleText
};
diff --git a/src/common/router/route.ts b/src/common/router/route.ts
index 9be7cb5..f38343e 100644
--- a/src/common/router/route.ts
+++ b/src/common/router/route.ts
@@ -32,6 +32,9 @@
/** A Preact view component. */
Component: Partial<AnyComponent<Props, any>>;
+
+ /** The document title shown in the browser window's title bar or tab. */
+ title?: (props: Props) => string | undefined;
}
| {
getInitialProps?: undefined;
@@ -43,6 +46,8 @@
status?: number;
Component: Partial<AnyComponent<undefined, any>>;
+
+ title?: () => string | undefined;
};
export interface PageModule<Params, Props> {
diff --git a/src/common/router/router.ts b/src/common/router/router.ts
index 0e5f69f..21326c2 100644
--- a/src/common/router/router.ts
+++ b/src/common/router/router.ts
@@ -9,11 +9,12 @@
chunkName?: string;
status: number;
Component: AnyComponent<Props, any>;
+ title?: (props: Props) => string | undefined;
props: Props;
}
-interface RequestPageModule {
- (name: string): Promise<PageModule<any, any>>;
+interface RequestPageModule<Params, Props> {
+ (name: string): Promise<PageModule<Params, Props>>;
}
function getInitialProps<Params, Props>(
@@ -36,7 +37,7 @@
}
function respond<Params, Props>(
- requestPageModule: RequestPageModule,
+ requestPageModule: RequestPageModule<Params, Props>,
route: Route<Params>,
params: Params
): Promise<RouteResponse<Props>> {
@@ -49,7 +50,8 @@
chunkName: `pages/${route.page}`,
status: (response && response.status) || module.default.status || 200,
Component: module.default.Component as AnyComponent<Props, any>,
- props: (response && response.data) as Props
+ props: (response && response.data) as Props,
+ title: module.default.title
}))
);
}
@@ -61,7 +63,8 @@
return Promise.resolve({
status: notFoundPage.status,
Component: notFoundPage.Component,
- props
+ props,
+ title: notFoundPage.title
});
}
@@ -78,12 +81,17 @@
const status = error instanceof FetchError ? error.status : errorPage.status;
const props: ErrorProps = { error };
- return Promise.resolve({ status, Component: errorPage.Component, props });
+ return Promise.resolve({
+ status,
+ Component: errorPage.Component,
+ props,
+ title: errorPage.title
+ });
}
export function newRouter(
routes: Route<any>[],
- requestPageModule: RequestPageModule = requestPageModuleChunk
+ requestPageModule: RequestPageModule<any, any> = requestPageModuleChunk
) {
return {
route(path: string): Promise<RouteResponse<any>> {
diff --git a/src/server/components/html-page.tsx
b/src/server/components/html-page.tsx
index 12fcdb6..8c5f32b 100644
--- a/src/server/components/html-page.tsx
+++ b/src/server/components/html-page.tsx
@@ -23,7 +23,7 @@
: undefined;
export default function HTMLPage({
- title = "",
+ title,
chunkName,
ssrData,
children
@@ -49,7 +49,7 @@
<meta charSet="utf-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
- <title>{title ? `${title} - ` : ""}Marvin</title>
+ <title>{title}</title>
{/* Preload the stylesheet before the scripts */}
<link rel="preload" href={style} as="style" />
<link rel="stylesheet" href={style} />
diff --git a/src/server/index.tsx b/src/server/index.tsx
index efcc6c8..efb75bb 100644
--- a/src/server/index.tsx
+++ b/src/server/index.tsx
@@ -7,6 +7,7 @@
import { routes } from "../common/router/routes";
import { SERVER_PORT, SERVER_URL } from "../common/assets/config";
import ErrorPage from "../common/pages/error";
+import { formatDocTitle } from "../common/format-doc-title";
import HTMLPage from "./components/html-page";
const server = express();
@@ -19,18 +20,17 @@
server.use("/public", express.static("dist/public"));
-function render({ chunkName, Component, props }: RouteResponse<any>) {
+function render({ chunkName, Component, props, title }: RouteResponse<any>) {
+ const docTitle = formatDocTitle(title ? title(props) : undefined);
// When an unexpected error occurs, forbid client re-rendering so that the
// original error can be shown.
const forceSSR = Component === ErrorPage.Component;
- return (
- "<!doctype html>" + // eslint-disable-line prefer-template
- renderToString(
- <HTMLPage title="" chunkName={chunkName} ssrData={{ forceSSR }}>
- <Component {...props} />
- </HTMLPage>
- )
+ const html = renderToString(
+ <HTMLPage title={docTitle} chunkName={chunkName} ssrData={{ forceSSR }}>
+ <Component {...props} />
+ </HTMLPage>
);
+ return `<!doctype html>${html}`;
}
const router = newRouter(routes);
diff --git a/test/server/components/html-page.test.ts
b/test/server/components/html-page.test.ts
index ef48709..ecaf5f1 100644
--- a/test/server/components/html-page.test.ts
+++ b/test/server/components/html-page.test.ts
@@ -25,7 +25,7 @@
ssrData: { forceSSR: false }
});
const html = render(vNode);
- const expected = "<title>Test - Marvin</title>";
+ const expected = "<title>Test</title>";
assert.ok(
html.includes(expected),
`Could not find \n\n${expected}\n\nin\n\n${html}`
--
To view, visit https://gerrit.wikimedia.org/r/396418
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I46bd5ded51df65651045613ea0b588d48f5c1847
Gerrit-PatchSet: 1
Gerrit-Project: marvin
Gerrit-Branch: master
Gerrit-Owner: Niedzielski <[email protected]>
Gerrit-Reviewer: Jhernandez <[email protected]>
Gerrit-Reviewer: Sniedzielski <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits