cavallium-website/src/app/services/document-fetch.service.ts

93 lines
3.0 KiB
TypeScript

import { Injectable } from "@angular/core";
import { DocumentData } from "../symbols/DocumentData";
import { HttpClient } from "@angular/common/http";
import { take } from "rxjs/operators";
@Injectable({
providedIn: "root"
})
export class DocumentFetchService {
private language: string;
private readonly replacements: {tag: string, replacement: string, single?: boolean}[] = [
{tag: "warning", replacement: "<span class=\"document-style-warning\">$1</span>"},
{tag: "inverted", replacement: "<span class=\"document-style-inverted\">$1</span>"},
{tag: "u", replacement: "<u>$1</u>"},
{tag: "br", replacement: "<br>", single: true}
];
constructor(private http: HttpClient) {
this.language = document.body.parentElement.lang;
}
public async fetch(unsafeId: string): Promise<DocumentData> {
const encodedId = this.encodeId(unsafeId);
try {
return await this.fetchWithLanguage(encodedId, this.language);
} catch (e) {
try {
return await this.fetchWithLanguage(encodedId, "en");
} catch (e) {
return {
found: false,
id: encodedId,
content: await this.fetchErrorContent(404)
};
}
}
}
private async fetchWithLanguage(unsafeId: string, language: string): Promise<DocumentData> {
const encodedId = this.encodeId(unsafeId);
const response: string = await this.http.get("/documents/" + encodedId + "." + language + ".md", { responseType: "text" })
.pipe(take(1)).toPromise();
return {
found: true,
id: encodedId,
content: this.format(await response)
};
}
public async fetchErrorContent(errorCode: number): Promise<string> {
if (errorCode > 0 && errorCode <= 700) {
try {
const response: string = await this.http.get("/documents/" + errorCode + "." + this.language + ".md", { responseType: "text" })
.pipe(take(1)).toPromise();
return this.format(await response);
} catch (e) {
}
}
return "Error " + errorCode + ".";
}
private encodeId(id: string): string {
const encoded = id.split("/").map(encodeURIComponent).filter((part) => part.length > 0 && !/[^a-zA-Z0-9_-àùéèì]/.test(part)).join("/");
if (encoded.length > 0) {
return encoded;
} else {
return "index";
}
}
private format(rawDocument: string): string {
let count: number;
do {
count = 0;
this.replacements.forEach(replacement => {
const replacementResult = this.replaceTagWith(rawDocument, replacement.tag, replacement.replacement,replacement.single);
count += replacementResult.count;
rawDocument = replacementResult.document;
});
} while (count > 0);
return rawDocument;
}
private replaceTagWith(document: string, tagName: string, tagResult: string, single?: boolean): {document: string, count: number} {
const newDocument = single === true ?
document.replace(new RegExp("\\[" + tagName + "\\]", "g"), tagResult)
:
document.replace(new RegExp("\\[" + tagName + "\\]([^[]+)\\[\\/" + tagName + "\\]", "g"), tagResult);
return {document: newDocument, count: newDocument !== document ? 1 : 0};
}
}