Skip to content

Commit

Permalink
feat: introduce DocumentMetaMiddleware
Browse files Browse the repository at this point in the history
  • Loading branch information
fquffio committed Sep 27, 2021
1 parent bb6bb33 commit 387867f
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 0 deletions.
103 changes: 103 additions & 0 deletions src/Router/DocumentMetaMiddleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { Middleware } from './Middleware';
import { Request } from './Request';
import { Meta, Response } from './Response';

export type TitleBuilder = (title: string | undefined, response: Response) => string;
export type MetaBuilder = (meta: Meta|undefined, response: Response) => Meta;

/**
* Middleware to set the document title and meta tags upon navigation.
*/
export class DocumentMetaMiddleware extends Middleware{
/**
* Get the owner document.
*/
protected document?: Document;

/**
* Title builder function.
*/
protected titleBuilder: TitleBuilder;

/**
* Meta builder function.
*/
protected metaBuilder: MetaBuilder;

/**
* Meta tags from last invocation.
*/
protected currentMeta: Meta = {};

/**
* Middleware rule constructor.
* @param document The owner document.
* @param titleBuilder The title builder function.
* @param metaBuilder The meta builder function.
*/
public constructor(document: Document | undefined = window.document, titleBuilder?: TitleBuilder, metaBuilder?: MetaBuilder) {
super({});

this.document = document;
this.titleBuilder = titleBuilder || ((title) => title || '');
this.metaBuilder = metaBuilder || ((meta) => meta || {});
}

/**
* Set document title and meta tags.
* @inheritdoc
*/
public hookAfter(request: Readonly<Request>, response: Response): Response {
this.setTitle(this.titleBuilder(response.title, response));
this.setMeta(this.metaBuilder(response.meta, response));

return response;
}

/**
* Update title.
* @param string The title string.
*/
protected setTitle(title: string): void {
if (this.document === undefined) {
return;
}

this.document.title = title;
}

/**
* Update meta tags.
* @param current Metadata for current state.
* @param previous Previous metadata.
*/
protected setMeta(meta: Meta): void {
if (this.document === undefined) {
return;
}

const head = this.document.head;
Object.entries(meta).forEach(([name, content]) => {
let meta = head.querySelector(`meta[name="${name}"]`);
if (meta !== null) {
meta.setAttribute('content', content);

return;
}

meta = head.ownerDocument.createElement('meta');
meta.setAttribute('name', name);
meta.setAttribute('content', content);
head.appendChild(meta);
});

Object.keys(this.currentMeta)
.filter((name) => !(name in meta))
.forEach((name) => {
const meta = head.querySelector(`meta[name="${name}"]`);
if (meta !== null) {
meta.remove();
}
});
}
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export { History } from './Router/History';
export { Router } from './Router/Router';
export { App } from './App';
export * from './helpers';
export { DocumentMetaMiddleware } from './Router/DocumentMetaMiddleware';

0 comments on commit 387867f

Please sign in to comment.