@rr0/cms
Version:
RR0 Content Management System (CMS)
131 lines (130 loc) • 5.37 kB
JavaScript
import fs from "fs";
import path from "path";
import { FileContents } from "@javarome/fileutil";
import { DirectoryStep } from "ssg-api";
import { RR0FileUtil } from "../util/file/RR0FileUtil.js";
import { StringUtil } from "../util/string/StringUtil.js";
import { HtmlTag } from "../util/html/HtmlTag.js";
import { Chapter } from "./Chapters.js";
/**
* Scan directories for book information, then populates a template with collected data.
*/
export class BookDirectoryStep extends DirectoryStep {
constructor(rootDirs, templateFileName, outputFunc, config, name, bookMeta, bookLinks) {
super({ rootDirs, excludedDirs: [], templateFileName, getOutputPath: config.getOutputPath }, name);
this.outputFunc = outputFunc;
this.bookMeta = bookMeta;
this.bookLinks = bookLinks;
}
static async create(outputFunc, config, bookMeta, bookLinks) {
const dirs = RR0FileUtil.findDirectoriesContaining("book*.json");
return new BookDirectoryStep(dirs, "book/index.html", outputFunc, config, "all books", bookMeta, bookLinks);
}
async processDirs(context, dirNames) {
const books = this.scan(context, dirNames);
await this.tocAll(context, books);
const directoriesHtml = this.toList(books);
context.file.contents = context.file.contents.replace(`<!--#echo var="directories" -->`, directoriesHtml);
await this.outputFunc(context, context.file);
}
scan(context, dirNames) {
const books = [];
for (const dirName of dirNames) {
const dirBook = {
events: [], previousSourceRefs: [], type: "book",
dirName,
authors: [],
publication: { publisher: "", time: undefined },
summary: "",
title: "",
variants: []
};
books.push(dirBook);
try {
const jsonFileInfo = FileContents.read(`${dirName}/book.json`);
Object.assign(dirBook, JSON.parse(jsonFileInfo.contents));
}
catch (e) {
context.warn(`${dirName} has no book*.json description`);
}
}
return books;
}
/**
* Convert an array of Case[] to an <ul> HTML unordered list.
*
* @param books
*/
toList(books) {
const listItems = books.map(dirBook => {
if (!dirBook.title) {
const lastSlash = dirBook.dirName.lastIndexOf("/");
const lastDir = dirBook.dirName.substring(lastSlash + 1);
dirBook.title = StringUtil.camelToText(lastDir);
}
return this.toListItem(dirBook);
});
return HtmlTag.toString("ul", listItems.join("\n"), { class: "links" });
}
/**
* Convert a Case object to an HTML list item.
*
* @param dirBook
*/
toListItem(dirBook) {
const attrs = {};
const titles = [];
const details = [];
const authors = dirBook.authors;
const authorStr = authors ? authors.join(" & ") + ": " : "";
const time = dirBook.publication.time;
if (time) {
const timeDetail = time.year.value;
details.push(HtmlTag.toString("time", timeDetail.toString()));
}
const text = [authorStr, dirBook.title];
if (details.length > 0) {
text.push(`(${details.join(", ")})`);
}
const innerHTML = text.join(" ").trim();
const a = fs.existsSync(path.join(dirBook.dirName, "index.html")) ? HtmlTag.toString("a", innerHTML, { href: "/" + dirBook.dirName + "/" }) : innerHTML;
if (titles.length) {
attrs.title = titles.join(", ");
}
return HtmlTag.toString("li", a, attrs);
}
async tocAll(context, books) {
for (const book of books) {
await this.toc(context, book);
}
}
async toc(context, book) {
const startFileName = path.join(book.dirName, "index.html");
try {
context.read(startFileName);
const startFileNames = [context.file.name];
const variants = context.file.lang.variants;
for (const variant of variants) {
const parsed = path.parse(startFileName);
const variantFileName = path.join(parsed.dir, `${parsed.name}_${variant}${parsed.ext}`);
startFileNames.push(variantFileName);
}
for (const startFileName of startFileNames) {
const chapter = new Chapter(context, startFileName);
await chapter.scan();
const chapterBefore = chapter.toString();
context.logger.debug("toc before:", chapterBefore);
await chapter.update();
const chapterAfter = chapter.toString();
context.logger.debug("toc after:", chapterAfter);
context.logger.log("Updated toc for", chapter.context.file.name);
book.variants.push(chapter);
this.bookMeta.set(startFileName, chapter.context.file.meta);
this.bookLinks.set(startFileName, chapter.context.file.links);
}
}
catch (e) {
context.logger.error("Could not check TOC of " + startFileName, e.message);
}
}
}