93 lines
3.0 KiB
TypeScript
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};
|
|
}
|
|
}
|