@ca-plant-list/ca-plant-list 0.3.7 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +7 -1
- package/data/synonyms.csv +85 -2
- package/data/taxa.csv +38 -16
- package/data/text/Antennaria-media.md +1 -0
- package/data/text/Antennaria-rosea-subsp-rosea.md +1 -0
- package/data/text/Camassia-leichtlinii-subsp-suksdorfii.md +1 -0
- package/data/text/Camassia-quamash-subsp-breviflora.md +1 -0
- package/data/text/Delphinium-glaucum.md +1 -0
- package/data/text/Delphinium-nuttallianum.md +1 -0
- package/data/text/Drymocallis-glandulosa-var-glandulosa.md +1 -0
- package/data/text/Drymocallis-lactea-var-austiniae.md +1 -0
- package/data/text/Erigeron-compositus.md +1 -0
- package/data/text/Erigeron-glacialis-var-glacialis.md +1 -0
- package/data/text/Erythranthe-breweri.md +1 -0
- package/data/text/Erythranthe-erubescens.md +1 -0
- package/data/text/Navarretia-leptalea-subsp-bicolor.md +1 -0
- package/data/text/Navarretia-leptalea-subsp-leptalea.md +1 -0
- package/data/text/Polemonium-californicum.md +1 -0
- package/data/text/Polemonium-pulcherrimum-var-pulcherrimum.md +1 -0
- package/data/text/Primula-jeffreyi.md +1 -0
- package/data/text/Primula-tetrandra.md +1 -0
- package/lib/basepagerenderer.js +3 -4
- package/lib/config.js +42 -19
- package/lib/csv.js +54 -36
- package/lib/ebook/ebook.js +84 -57
- package/lib/ebook/ebookpage.js +22 -11
- package/lib/ebook/ebooksitegenerator.js +36 -14
- package/lib/ebook/glossarypages.js +20 -17
- package/lib/ebook/images.js +13 -5
- package/lib/ebook/pages/page_list_families.js +0 -2
- package/lib/ebook/pages/page_list_flower_color.js +14 -9
- package/lib/ebook/pages/page_list_flowers.js +59 -41
- package/lib/ebook/pages/taxonpage.js +1 -1
- package/lib/ebook/pages/tocpage.js +26 -20
- package/lib/ebook/plantbook.js +6 -13
- package/lib/ebook/{image.js → taxonimage.js} +2 -2
- package/lib/exceptions.js +42 -26
- package/lib/externalsites.js +11 -4
- package/lib/families.js +10 -8
- package/lib/flowercolor.js +42 -0
- package/lib/genera.js +13 -21
- package/lib/genericpage.js +12 -0
- package/lib/html.js +11 -23
- package/lib/htmltaxon.js +89 -6
- package/lib/index.d.ts +54 -0
- package/lib/index.js +2 -30
- package/lib/jekyll.js +49 -21
- package/lib/jepson.js +7 -8
- package/lib/markdown.js +6 -0
- package/lib/pagerenderer.js +43 -8
- package/lib/plants/glossary.js +5 -0
- package/lib/program.js +47 -0
- package/lib/rareplants.js +44 -30
- package/lib/sitegenerator.js +41 -24
- package/lib/taxa.js +20 -134
- package/lib/taxon.js +1 -1
- package/lib/web/glossarypages.js +6 -0
- package/lib/web/pagetaxon.js +1 -5
- package/package.json +6 -3
- package/schemas/exceptions.schema.json +57 -0
- package/scripts/build-ebook.js +38 -47
- package/scripts/build-site.js +25 -14
- package/types/classes.d.ts +136 -8
- package/lib/commandandtaxaprocessor.js +0 -25
- package/lib/commandprocessor.js +0 -108
- package/lib/generictaxaloader.js +0 -48
- package/lib/taxaloader.js +0 -50
- package/lib/taxaprocessor.js +0 -34
- /package/data/text/{Calyptridium-ubellatum.md → Calyptridium-umbellatum.md} +0 -0
package/lib/config.js
CHANGED
@@ -3,46 +3,69 @@ import * as url from "node:url";
|
|
3
3
|
import { Files } from "./files.js";
|
4
4
|
|
5
5
|
class Config {
|
6
|
+
static #packageDir = path.dirname(
|
7
|
+
path.dirname(url.fileURLToPath(import.meta.url))
|
8
|
+
);
|
6
9
|
|
7
|
-
|
8
|
-
|
10
|
+
/** @type {Object<string,Object<string,Object<string,{}>>>} */
|
9
11
|
#config = {};
|
10
12
|
|
11
|
-
|
12
|
-
|
13
|
+
/**
|
14
|
+
* @param {string} dataDir
|
15
|
+
*/
|
16
|
+
constructor(dataDir) {
|
17
|
+
this.#config = JSON.parse(Files.read(dataDir + "/config.json"));
|
13
18
|
}
|
14
19
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
/**
|
21
|
+
* @param {string} prefix
|
22
|
+
* @param {string} name
|
23
|
+
* @param {string|undefined} subcat
|
24
|
+
* @param {string} dflt
|
25
|
+
* @returns {string}
|
26
|
+
*/
|
27
|
+
getConfigValue(prefix, name, subcat, dflt) {
|
28
|
+
const obj = this.#config[prefix];
|
29
|
+
if (obj) {
|
30
|
+
if (Object.hasOwn(obj, name)) {
|
31
|
+
const nameObj = obj[name];
|
32
|
+
if (nameObj === undefined) {
|
21
33
|
return dflt;
|
22
34
|
}
|
23
|
-
if (
|
24
|
-
return nameObj;
|
35
|
+
if (subcat === undefined) {
|
36
|
+
return typeof nameObj === "string" ? nameObj : dflt;
|
25
37
|
}
|
26
|
-
if (
|
27
|
-
|
38
|
+
if (Object.hasOwn(nameObj, subcat)) {
|
39
|
+
const v = nameObj[subcat];
|
40
|
+
return typeof v === "string" ? v : dflt;
|
28
41
|
}
|
29
42
|
}
|
30
43
|
}
|
31
44
|
return dflt;
|
32
45
|
}
|
33
46
|
|
47
|
+
/**
|
48
|
+
* @returns {string[]}
|
49
|
+
*/
|
34
50
|
getCountyCodes() {
|
35
|
-
|
51
|
+
const counties = this.#config["counties"];
|
52
|
+
if (counties instanceof Array) {
|
53
|
+
return counties;
|
54
|
+
}
|
55
|
+
return [];
|
36
56
|
}
|
37
57
|
|
38
|
-
|
39
|
-
|
58
|
+
/**
|
59
|
+
* @param {string} name
|
60
|
+
* @param {string} dflt
|
61
|
+
*/
|
62
|
+
getLabel(name, dflt) {
|
63
|
+
return this.getConfigValue("labels", name, undefined, dflt);
|
40
64
|
}
|
41
65
|
|
42
66
|
static getPackageDir() {
|
43
67
|
return this.#packageDir;
|
44
68
|
}
|
45
|
-
|
46
69
|
}
|
47
70
|
|
48
|
-
export { Config };
|
71
|
+
export { Config };
|
package/lib/csv.js
CHANGED
@@ -5,81 +5,99 @@ import { parse as parseSync } from "csv-parse/sync";
|
|
5
5
|
import { parse } from "csv-parse";
|
6
6
|
|
7
7
|
class CSV {
|
8
|
+
/**
|
9
|
+
* @param {string} dir
|
10
|
+
* @param {string} fileName
|
11
|
+
*/
|
12
|
+
static getMap(dir, fileName) {
|
13
|
+
/** @type {string[]} */
|
14
|
+
let headers = [];
|
8
15
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
function setHeaders( h ) {
|
16
|
+
/**
|
17
|
+
* @param {string[]} h
|
18
|
+
*/
|
19
|
+
function setHeaders(h) {
|
14
20
|
headers = h;
|
15
21
|
return h;
|
16
22
|
}
|
17
23
|
|
18
|
-
const csv = this.parseFile(
|
24
|
+
const csv = this.parseFile(dir, fileName, setHeaders);
|
25
|
+
/** @type {Object<string,string[]>} */
|
19
26
|
const map = {};
|
20
|
-
for (
|
21
|
-
map[
|
27
|
+
for (const row of csv) {
|
28
|
+
map[row[headers[0]]] = row[headers[1]];
|
22
29
|
}
|
23
30
|
|
24
31
|
return map;
|
25
32
|
}
|
26
33
|
|
27
|
-
|
34
|
+
/**
|
35
|
+
* @param {string} fileName
|
36
|
+
* @param {import("csv-parse").ColumnOption[]|boolean|function (string[]):string[]} columns
|
37
|
+
* @param {string|undefined} delimiter
|
38
|
+
*/
|
39
|
+
static #getOptions(fileName, columns, delimiter) {
|
40
|
+
/** @type {import("csv-parse").Options} */
|
28
41
|
const options = { relax_column_count_less: true };
|
29
42
|
options.columns = columns;
|
30
|
-
if (
|
43
|
+
if (path.extname(fileName) === ".tsv") {
|
31
44
|
options.delimiter = "\t";
|
32
45
|
options.quote = false;
|
33
46
|
} else {
|
34
47
|
options.delimiter = delimiter ? delimiter : ",";
|
35
48
|
}
|
36
|
-
if (
|
49
|
+
if (options.delimiter === "\t") {
|
37
50
|
options.quote = null;
|
38
51
|
}
|
39
52
|
return options;
|
40
53
|
}
|
41
54
|
|
42
55
|
/**
|
43
|
-
* @param {string} dir
|
44
|
-
* @param {string} fileName
|
45
|
-
* @param {boolean|
|
46
|
-
* @param {string
|
56
|
+
* @param {string} dir
|
57
|
+
* @param {string} fileName
|
58
|
+
* @param {boolean|import("csv-parse").ColumnOption[]|function (string[]):string[]} [columns]
|
59
|
+
* @param {string} [delimiter]
|
47
60
|
*/
|
48
|
-
static parseFile(
|
49
|
-
const content = fs.readFileSync(
|
61
|
+
static parseFile(dir, fileName, columns = true, delimiter) {
|
62
|
+
const content = fs.readFileSync(dir + "/" + fileName);
|
50
63
|
|
51
|
-
const options = this.#getOptions(
|
52
|
-
return parseSync(
|
64
|
+
const options = this.#getOptions(fileName, columns, delimiter);
|
65
|
+
return parseSync(content, options);
|
53
66
|
}
|
54
67
|
|
55
68
|
/**
|
56
|
-
* @param {string} dir
|
57
|
-
* @param {string} fileName
|
58
|
-
* @param {boolean|
|
59
|
-
* @param {string|undefined} delimiter
|
60
|
-
* @param {
|
69
|
+
* @param {string} dir
|
70
|
+
* @param {string} fileName
|
71
|
+
* @param {boolean|import("csv-parse").ColumnOption[]} columns
|
72
|
+
* @param {string|undefined} delimiter
|
73
|
+
* @param {function (any):void} callback
|
61
74
|
*/
|
62
|
-
static async parseStream(
|
63
|
-
|
75
|
+
static async parseStream(
|
76
|
+
dir,
|
77
|
+
fileName,
|
78
|
+
columns = true,
|
79
|
+
delimiter,
|
80
|
+
callback
|
81
|
+
) {
|
82
|
+
const options = this.#getOptions(fileName, columns, delimiter);
|
64
83
|
const processFile = async () => {
|
84
|
+
/** @type {string[][]} */
|
65
85
|
const records = [];
|
66
86
|
const parser = fs
|
67
|
-
.createReadStream(
|
68
|
-
.pipe(
|
69
|
-
parser.on(
|
87
|
+
.createReadStream(dir + "/" + fileName)
|
88
|
+
.pipe(parse(options));
|
89
|
+
parser.on("readable", function () {
|
70
90
|
let record;
|
71
|
-
while (
|
72
|
-
callback(
|
91
|
+
while ((record = parser.read()) !== null) {
|
92
|
+
callback(record);
|
73
93
|
}
|
74
|
-
}
|
75
|
-
await finished(
|
94
|
+
});
|
95
|
+
await finished(parser);
|
76
96
|
return records;
|
77
97
|
};
|
78
98
|
// Parse the CSV content
|
79
99
|
await processFile();
|
80
|
-
|
81
100
|
}
|
82
|
-
|
83
101
|
}
|
84
102
|
|
85
|
-
export { CSV };
|
103
|
+
export { CSV };
|
package/lib/ebook/ebook.js
CHANGED
@@ -9,34 +9,40 @@ const MEDIA_TYPES = {
|
|
9
9
|
XHTML: "application/xhtml+xml",
|
10
10
|
};
|
11
11
|
|
12
|
+
/**
|
13
|
+
* @type {Object<string,string>}
|
14
|
+
*/
|
12
15
|
const EXT_MEDIA_MAP = {
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
jpeg: MEDIA_TYPES.JPG,
|
17
|
+
jpg: MEDIA_TYPES.JPG,
|
18
|
+
svg: MEDIA_TYPES.SVG,
|
16
19
|
};
|
17
20
|
|
18
21
|
class EBook {
|
19
|
-
|
20
22
|
#outputDir;
|
21
23
|
#filename;
|
22
24
|
#pub_id;
|
23
25
|
#title;
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
+
/**
|
28
|
+
*
|
29
|
+
* @param {string} outputDir
|
30
|
+
* @param {string} filename
|
31
|
+
* @param {string} pub_id
|
32
|
+
* @param {string} title
|
33
|
+
*/
|
34
|
+
constructor(outputDir, filename, pub_id, title) {
|
27
35
|
this.#outputDir = outputDir;
|
28
36
|
this.#filename = filename;
|
29
37
|
this.#pub_id = pub_id;
|
30
38
|
this.#title = title;
|
31
39
|
|
32
40
|
// Initialize output directory.
|
33
|
-
fs.rmSync(
|
34
|
-
fs.mkdirSync(
|
35
|
-
|
41
|
+
fs.rmSync(this.#outputDir, { force: true, recursive: true });
|
42
|
+
fs.mkdirSync(this.getContentDir(), { recursive: true });
|
36
43
|
}
|
37
44
|
|
38
45
|
async create() {
|
39
|
-
|
40
46
|
const contentDir = this.getContentDir();
|
41
47
|
|
42
48
|
this.#createContainerFile();
|
@@ -44,36 +50,35 @@ class EBook {
|
|
44
50
|
this.#createPackageFile();
|
45
51
|
|
46
52
|
// Copy assets
|
47
|
-
|
48
|
-
|
49
|
-
|
53
|
+
fs.cpSync(Config.getPackageDir() + "/ebook", contentDir, {
|
54
|
+
recursive: true,
|
55
|
+
});
|
50
56
|
|
51
57
|
this.createZip();
|
52
|
-
|
53
58
|
}
|
54
59
|
|
55
60
|
#createContainerFile() {
|
56
|
-
|
57
61
|
const metaDir = this.#getMetaDir();
|
58
62
|
|
59
|
-
fs.mkdirSync(
|
63
|
+
fs.mkdirSync(metaDir, { recursive: true });
|
60
64
|
|
61
|
-
let xml =
|
62
|
-
|
65
|
+
let xml =
|
66
|
+
'<?xml version="1.0"?>' +
|
67
|
+
'<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">';
|
63
68
|
|
64
|
-
xml +=
|
69
|
+
xml +=
|
70
|
+
'<rootfiles><rootfile full-path="epub/package.opf" media-type="application/oebps-package+xml" /></rootfiles>';
|
65
71
|
xml += "</container>";
|
66
72
|
|
67
|
-
fs.writeFileSync(
|
68
|
-
|
73
|
+
fs.writeFileSync(metaDir + "/container.xml", xml);
|
69
74
|
}
|
70
75
|
|
71
76
|
#createPackageFile() {
|
72
|
-
|
73
77
|
const dir = this.getContentDir();
|
74
78
|
|
75
|
-
let xml =
|
76
|
-
|
79
|
+
let xml =
|
80
|
+
'<?xml version="1.0"?>\n' +
|
81
|
+
'<package version="3.0" xml:lang="en" xmlns="http://www.idpf.org/2007/opf" unique-identifier="pub-id">';
|
77
82
|
|
78
83
|
xml += this.#renderMetadata();
|
79
84
|
xml += this.#renderManifest();
|
@@ -81,50 +86,67 @@ class EBook {
|
|
81
86
|
|
82
87
|
xml += "</package>";
|
83
88
|
|
84
|
-
fs.writeFileSync(
|
85
|
-
|
89
|
+
fs.writeFileSync(dir + "/package.opf", xml);
|
86
90
|
}
|
87
91
|
|
88
92
|
async createPages() {
|
89
|
-
throw new Error(
|
93
|
+
throw new Error("must be implemented by subclass");
|
90
94
|
}
|
91
95
|
|
92
96
|
createZip() {
|
93
97
|
// Create zip.
|
94
98
|
const filename = this.#outputDir + "/" + this.#filename + ".epub";
|
95
|
-
const output = fs.createWriteStream(
|
96
|
-
const archive = archiver(
|
97
|
-
|
98
|
-
|
99
|
-
zlib: { level: 9 } // Sets the compression level.
|
100
|
-
}
|
101
|
-
);
|
99
|
+
const output = fs.createWriteStream(filename);
|
100
|
+
const archive = archiver("zip", {
|
101
|
+
zlib: { level: 9 }, // Sets the compression level.
|
102
|
+
});
|
102
103
|
|
103
|
-
archive.pipe(
|
104
|
+
archive.pipe(output);
|
104
105
|
|
105
|
-
archive.append(
|
106
|
+
archive.append("application/epub+zip", {
|
107
|
+
name: "mimetype",
|
108
|
+
store: true,
|
109
|
+
});
|
106
110
|
|
107
|
-
archive.directory(
|
108
|
-
archive.directory(
|
111
|
+
archive.directory(this.#getMetaDir(), "META-INF");
|
112
|
+
archive.directory(this.getContentDir(), "epub");
|
109
113
|
|
110
114
|
archive.finalize();
|
111
|
-
|
112
115
|
}
|
113
116
|
|
114
117
|
getContentDir() {
|
115
118
|
return this.#outputDir + "/epub";
|
116
119
|
}
|
117
120
|
|
118
|
-
|
119
|
-
|
121
|
+
/**
|
122
|
+
* @param {string} id
|
123
|
+
* @param {string} href
|
124
|
+
* @param {string} mediaType
|
125
|
+
*/
|
126
|
+
static getManifestEntry(id, href, mediaType = MEDIA_TYPES.XHTML) {
|
127
|
+
return (
|
128
|
+
'<item id="' +
|
129
|
+
id +
|
130
|
+
'" href="' +
|
131
|
+
href +
|
132
|
+
'" media-type="' +
|
133
|
+
mediaType +
|
134
|
+
'" />'
|
135
|
+
);
|
120
136
|
}
|
121
137
|
|
122
|
-
|
123
|
-
|
138
|
+
/**
|
139
|
+
* @param {string} ext
|
140
|
+
*/
|
141
|
+
static getMediaTypeForExt(ext) {
|
142
|
+
return EXT_MEDIA_MAP[ext];
|
124
143
|
}
|
125
144
|
|
126
|
-
|
127
|
-
|
145
|
+
/**
|
146
|
+
* @param {string} id
|
147
|
+
*/
|
148
|
+
static getSpineEntry(id) {
|
149
|
+
return '<itemref idref="' + id + '"/>';
|
128
150
|
}
|
129
151
|
|
130
152
|
#getMetaDir() {
|
@@ -133,38 +155,43 @@ class EBook {
|
|
133
155
|
|
134
156
|
#renderManifest() {
|
135
157
|
let xml = "<manifest>";
|
136
|
-
xml +=
|
158
|
+
xml += '<item id="c0" href="css/main.css" media-type="text/css" />';
|
137
159
|
xml += this.renderManifestEntries();
|
138
|
-
xml +=
|
160
|
+
xml +=
|
161
|
+
'<item id="toc" href="toc.xhtml" media-type="application/xhtml+xml" properties="nav" />';
|
139
162
|
return xml + "</manifest>";
|
140
163
|
}
|
141
164
|
|
142
165
|
renderManifestEntries() {
|
143
|
-
throw new Error(
|
166
|
+
throw new Error("must be implemented by subclass");
|
144
167
|
}
|
145
168
|
|
146
169
|
#renderMetadata() {
|
147
|
-
let xml =
|
148
|
-
xml += XHTML.textElement(
|
170
|
+
let xml = '<metadata xmlns:dc="http://purl.org/dc/elements/1.1/">';
|
171
|
+
xml += XHTML.textElement("dc:identifier", this.#pub_id, {
|
172
|
+
id: "pub-id",
|
173
|
+
});
|
149
174
|
xml += "<dc:language>en-US</dc:language>";
|
150
|
-
xml += XHTML.textElement(
|
175
|
+
xml += XHTML.textElement("dc:title", this.#title);
|
151
176
|
const d = new Date();
|
152
|
-
d.setUTCMilliseconds(
|
153
|
-
xml +=
|
177
|
+
d.setUTCMilliseconds(0);
|
178
|
+
xml +=
|
179
|
+
'<meta property="dcterms:modified">' +
|
180
|
+
d.toISOString().replace(".000", "") +
|
181
|
+
"</meta>";
|
154
182
|
return xml + "</metadata>";
|
155
183
|
}
|
156
184
|
|
157
185
|
#renderSpine() {
|
158
186
|
let xml = "<spine>";
|
159
|
-
xml +=
|
187
|
+
xml += '<itemref idref="toc"/>';
|
160
188
|
xml += this.renderSpineElements();
|
161
189
|
return xml + "</spine>";
|
162
190
|
}
|
163
191
|
|
164
192
|
renderSpineElements() {
|
165
|
-
throw new Error(
|
193
|
+
throw new Error("must be implemented by subclass");
|
166
194
|
}
|
167
|
-
|
168
195
|
}
|
169
196
|
|
170
|
-
export { EBook };
|
197
|
+
export { EBook };
|
package/lib/ebook/ebookpage.js
CHANGED
@@ -1,22 +1,27 @@
|
|
1
1
|
import * as fs from "node:fs";
|
2
2
|
|
3
3
|
class EBookPage {
|
4
|
-
|
5
4
|
#fileName;
|
6
5
|
#title;
|
7
6
|
#rootPrefix;
|
8
7
|
|
9
|
-
|
8
|
+
/**
|
9
|
+
*
|
10
|
+
* @param {string} fileName
|
11
|
+
* @param {string} title
|
12
|
+
* @param {string} rootPrefix
|
13
|
+
*/
|
14
|
+
constructor(fileName, title, rootPrefix = "") {
|
10
15
|
this.#fileName = fileName;
|
11
16
|
this.#title = title;
|
12
17
|
this.#rootPrefix = rootPrefix;
|
13
18
|
}
|
14
19
|
|
15
20
|
create() {
|
16
|
-
let html = this.#renderPageStart(
|
21
|
+
let html = this.#renderPageStart(this.#title);
|
17
22
|
html += this.renderPageBody();
|
18
23
|
html += this.#renderPageEnd();
|
19
|
-
fs.writeFileSync(
|
24
|
+
fs.writeFileSync(this.#fileName, html);
|
20
25
|
}
|
21
26
|
|
22
27
|
getTitle() {
|
@@ -28,22 +33,28 @@ class EBookPage {
|
|
28
33
|
}
|
29
34
|
|
30
35
|
renderPageBody() {
|
31
|
-
throw new Error(
|
36
|
+
throw new Error("must be implemented by subclass");
|
32
37
|
}
|
33
38
|
|
34
39
|
#renderPageEnd() {
|
35
40
|
return "</body></html>";
|
36
41
|
}
|
37
42
|
|
38
|
-
|
39
|
-
|
40
|
-
|
43
|
+
/**
|
44
|
+
* @param {string} title
|
45
|
+
*/
|
46
|
+
#renderPageStart(title) {
|
47
|
+
let html = '<?xml version="1.0" encoding="utf-8"?>\n';
|
48
|
+
html +=
|
49
|
+
'<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">';
|
41
50
|
html += "<head><title>" + title + "</title>";
|
42
|
-
html +=
|
51
|
+
html +=
|
52
|
+
'<link href="' +
|
53
|
+
this.#rootPrefix +
|
54
|
+
'css/main.css" rel="stylesheet" />';
|
43
55
|
html += "</head>" + this.#renderBodyStart();
|
44
56
|
return html;
|
45
57
|
}
|
46
|
-
|
47
58
|
}
|
48
59
|
|
49
|
-
export { EBookPage };
|
60
|
+
export { EBookPage };
|
@@ -2,33 +2,55 @@ import { Files } from "../files.js";
|
|
2
2
|
import { SiteGenerator } from "../sitegenerator.js";
|
3
3
|
|
4
4
|
class EBookSiteGenerator extends SiteGenerator {
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
/**
|
6
|
+
* @param {string} baseDir
|
7
|
+
*/
|
8
|
+
constructor(baseDir) {
|
9
|
+
super(baseDir);
|
8
10
|
}
|
9
11
|
|
10
12
|
#pageEnd() {
|
11
13
|
return "</body></html>";
|
12
14
|
}
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
/**
|
17
|
+
* @param {number} depth
|
18
|
+
* @param {{title:string}} attributes
|
19
|
+
*/
|
20
|
+
#pageStart(depth, attributes) {
|
21
|
+
let html = '<?xml version="1.0" encoding="utf-8"?>\n';
|
22
|
+
html +=
|
23
|
+
'<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">';
|
17
24
|
html += "<head><title>" + attributes.title + "</title>";
|
18
|
-
html +=
|
25
|
+
html +=
|
26
|
+
'<link href="' +
|
27
|
+
"../".repeat(depth) +
|
28
|
+
'css/main.css" rel="stylesheet" />';
|
19
29
|
html += "</head><body>";
|
20
30
|
return html;
|
21
31
|
}
|
22
32
|
|
23
|
-
|
24
|
-
|
33
|
+
/**
|
34
|
+
* @param {number} depth
|
35
|
+
* @param {string} content
|
36
|
+
* @param {{title:string}} attributes
|
37
|
+
*/
|
38
|
+
#wrap(depth, content, attributes) {
|
39
|
+
return this.#pageStart(depth, attributes) + content + this.#pageEnd();
|
25
40
|
}
|
26
41
|
|
27
|
-
|
28
|
-
|
29
|
-
|
42
|
+
/**
|
43
|
+
* @param {string} content
|
44
|
+
* @param {{title:string}} attributes
|
45
|
+
* @param {string} filename
|
46
|
+
*/
|
47
|
+
writeTemplate(content, attributes, filename) {
|
48
|
+
const depth = (filename.match(/\//g) || []).length;
|
49
|
+
Files.write(
|
50
|
+
Files.join(this.getBaseDir(), filename),
|
51
|
+
this.#wrap(depth, content, attributes)
|
52
|
+
);
|
30
53
|
}
|
31
|
-
|
32
54
|
}
|
33
55
|
|
34
|
-
export { EBookSiteGenerator };
|
56
|
+
export { EBookSiteGenerator };
|
@@ -2,39 +2,42 @@ import { GlossaryPages as BaseGlossaryPages } from "../web/glossarypages.js";
|
|
2
2
|
import { EBook } from "./ebook.js";
|
3
3
|
|
4
4
|
class GlossaryPages extends BaseGlossaryPages {
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
/**
|
6
|
+
* @param {SiteGenerator} siteGenerator
|
7
|
+
*/
|
8
|
+
constructor(siteGenerator) {
|
9
|
+
super(siteGenerator);
|
8
10
|
}
|
9
11
|
|
10
12
|
getManifestEntries() {
|
11
|
-
|
12
13
|
const glossaryEntries = this.getGlossary().getEntries();
|
13
14
|
const manifestEntries = [];
|
14
15
|
|
15
|
-
manifestEntries.push(
|
16
|
-
for (
|
17
|
-
const entry = glossaryEntries[
|
18
|
-
manifestEntries.push(
|
16
|
+
manifestEntries.push(EBook.getManifestEntry("g", "glossary.html"));
|
17
|
+
for (let index = 0; index < glossaryEntries.length; index++) {
|
18
|
+
const entry = glossaryEntries[index];
|
19
|
+
manifestEntries.push(
|
20
|
+
EBook.getManifestEntry(
|
21
|
+
"g" + index,
|
22
|
+
"g/" + entry.getHTMLFileName()
|
23
|
+
)
|
24
|
+
);
|
19
25
|
}
|
20
26
|
|
21
|
-
return manifestEntries.join(
|
27
|
+
return manifestEntries.join("");
|
22
28
|
}
|
23
29
|
|
24
30
|
getSpineEntries() {
|
25
|
-
|
26
31
|
const glossaryEntries = this.getGlossary().getEntries();
|
27
32
|
const spineEntries = [];
|
28
33
|
|
29
|
-
spineEntries.push(
|
30
|
-
for (
|
31
|
-
spineEntries.push(
|
34
|
+
spineEntries.push(EBook.getSpineEntry("g"));
|
35
|
+
for (let index = 0; index < glossaryEntries.length; index++) {
|
36
|
+
spineEntries.push(EBook.getSpineEntry("g" + index));
|
32
37
|
}
|
33
38
|
|
34
|
-
return spineEntries.join(
|
35
|
-
|
39
|
+
return spineEntries.join("");
|
36
40
|
}
|
37
|
-
|
38
41
|
}
|
39
42
|
|
40
|
-
export { GlossaryPages };
|
43
|
+
export { GlossaryPages };
|