@ca-plant-list/ca-plant-list 0.3.6 → 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 +109 -3
- package/data/taxa.csv +65 -29
- package/data/text/Antennaria-media.md +1 -0
- package/data/text/Antennaria-rosea-subsp-rosea.md +1 -0
- package/data/text/Antirrhinum-thompsonii.md +1 -0
- package/data/text/Calyptridium-monospermum.md +1 -0
- package/data/text/Calyptridium-umbellatum.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/Clarkia-affinis.md +1 -0
- package/data/text/Clarkia-breweri.md +1 -0
- package/data/text/Clarkia-concinna-subsp-automixa.md +1 -0
- package/data/text/Clarkia-modesta.md +1 -0
- package/data/text/Clarkia-purpurea-subsp-quadrivulnera.md +1 -0
- package/data/text/Clarkia-rubicunda.md +1 -0
- package/data/text/Delphinium-californicum-subsp-californicum.md +1 -1
- package/data/text/Delphinium-californicum-subsp-interius.md +1 -0
- package/data/text/Delphinium-glaucum.md +1 -0
- package/data/text/Delphinium-hesperium-subsp-hesperium.md +1 -1
- package/data/text/Delphinium-hesperium-subsp-pallescens.md +1 -0
- package/data/text/Delphinium-nuttallianum.md +1 -0
- package/data/text/Delphinium-parryi-subsp-parryi.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/Erythranthe-moschata.md +1 -0
- package/data/text/Erythranthe-primuloides.md +1 -0
- package/data/text/Erythranthe-tilingii.md +1 -0
- package/data/text/Lilium-pardalinum-subsp-shastense.md +1 -0
- package/data/text/Logfia-filaginoides.md +1 -0
- package/data/text/Logfia-gallica.md +1 -0
- package/data/text/Malacothamnus-arcuatus-var-elmeri.md +1 -0
- package/data/text/Malacothamnus-fremontii-var-fremontii.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/data/text/Trifolium-obtusiflorum.md +1 -0
- package/data/text/Trifolium-willdenovii.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 +59 -42
- 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/page_list_species.js +15 -9
- package/lib/ebook/pages/taxonpage.js +3 -6
- 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/ebook/xhtml.js +3 -5
- package/lib/exceptions.js +42 -26
- package/lib/externalsites.js +11 -4
- package/lib/families.js +10 -10
- package/lib/flowercolor.js +42 -0
- package/lib/genera.js +13 -23
- package/lib/genericpage.js +38 -18
- package/lib/html.js +11 -23
- package/lib/htmltaxon.js +114 -14
- 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 +13 -9
- package/lib/pagerenderer.js +162 -82
- package/lib/plants/glossary.js +14 -14
- package/lib/program.js +47 -0
- package/lib/rareplants.js +44 -30
- package/lib/sitegenerator.js +41 -24
- package/lib/taxa.js +25 -142
- package/lib/taxon.js +3 -5
- package/lib/web/glossarypages.js +37 -18
- package/lib/web/pagetaxon.js +1 -5
- package/package.json +5 -3
- package/schemas/exceptions.schema.json +57 -0
- package/scripts/build-ebook.js +39 -48
- package/scripts/build-site.js +49 -28
- package/types/classes.d.ts +154 -0
- package/lib/commandandtaxaprocessor.js +0 -25
- package/lib/commandprocessor.js +0 -108
- package/lib/generictaxaloader.js +0 -48
- package/lib/taxaloader.js +0 -48
- package/lib/taxaprocessor.js +0 -34
package/lib/exceptions.js
CHANGED
@@ -2,55 +2,71 @@ import { Config } from "./config.js";
|
|
2
2
|
import { Files } from "./files.js";
|
3
3
|
|
4
4
|
class Exceptions {
|
5
|
-
|
5
|
+
/** @type {Object<string,Object<string,Object<string,{}>>>} */
|
6
6
|
#exceptions = {};
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
/**
|
9
|
+
* @param {string} dir
|
10
|
+
*/
|
11
|
+
constructor(dir) {
|
12
|
+
/**
|
13
|
+
* @param {string} fileName
|
14
|
+
*/
|
15
|
+
function readConfig(fileName) {
|
16
|
+
return JSON.parse(Files.read(fileName));
|
12
17
|
}
|
13
18
|
|
14
19
|
// Read default configuration.
|
15
|
-
this.#exceptions = readConfig(
|
20
|
+
this.#exceptions = readConfig(
|
21
|
+
Config.getPackageDir() + "/data/exceptions.json"
|
22
|
+
);
|
16
23
|
|
17
24
|
// Add/overwrite with local configuration.
|
18
|
-
const localExceptions = readConfig(
|
19
|
-
for (
|
20
|
-
this.#exceptions[
|
25
|
+
const localExceptions = readConfig(dir + "/exceptions.json");
|
26
|
+
for (const [k, v] of Object.entries(localExceptions)) {
|
27
|
+
this.#exceptions[k] = v;
|
21
28
|
// Tag as a local exception so we can distinguish between global and local.
|
22
29
|
v.local = true;
|
23
30
|
}
|
24
|
-
|
25
31
|
}
|
26
32
|
|
27
33
|
getExceptions() {
|
28
|
-
return Object.entries(
|
34
|
+
return Object.entries(this.#exceptions);
|
29
35
|
}
|
30
36
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
37
|
+
/**
|
38
|
+
* @param {string} name
|
39
|
+
* @param {string} cat
|
40
|
+
* @param {string} subcat
|
41
|
+
* @param {string} defaultValue
|
42
|
+
*/
|
43
|
+
getValue(name, cat, subcat, defaultValue) {
|
44
|
+
const taxonData = this.#exceptions[name];
|
45
|
+
if (taxonData) {
|
46
|
+
const catData = taxonData[cat];
|
47
|
+
if (catData) {
|
48
|
+
const val = catData[subcat];
|
49
|
+
return val === undefined ? defaultValue : val;
|
38
50
|
}
|
39
51
|
}
|
40
52
|
return defaultValue;
|
41
53
|
}
|
42
54
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
55
|
+
/**
|
56
|
+
* @param {string} name
|
57
|
+
* @param {string} cat
|
58
|
+
* @param {string} subcat
|
59
|
+
*/
|
60
|
+
hasException(name, cat, subcat) {
|
61
|
+
const taxonData = this.#exceptions[name];
|
62
|
+
if (taxonData) {
|
63
|
+
const catData = taxonData[cat];
|
64
|
+
if (catData) {
|
65
|
+
return catData[subcat] !== undefined;
|
49
66
|
}
|
50
67
|
}
|
51
68
|
return false;
|
52
69
|
}
|
53
|
-
|
54
70
|
}
|
55
71
|
|
56
|
-
export { Exceptions };
|
72
|
+
export { Exceptions };
|
package/lib/externalsites.js
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
class ExternalSites {
|
2
|
+
/**
|
3
|
+
* @param {InatObsOptions} options
|
4
|
+
*/
|
2
5
|
static getInatObsLink(options) {
|
3
6
|
const url = new URL(
|
4
7
|
"https://www.inaturalist.org/observations?subview=map"
|
@@ -9,10 +12,14 @@ class ExternalSites {
|
|
9
12
|
case "coords": {
|
10
13
|
const delta = 0.1;
|
11
14
|
const params = url.searchParams;
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
/** @type {number} */
|
16
|
+
const lat = v[1];
|
17
|
+
/** @type {number} */
|
18
|
+
const lng = v[0];
|
19
|
+
params.set("nelat", (lat + delta).toString());
|
20
|
+
params.set("swlat", (lat - delta).toString());
|
21
|
+
params.set("nelng", (lng + delta).toString());
|
22
|
+
params.set("swlng", (lng - delta).toString());
|
16
23
|
break;
|
17
24
|
}
|
18
25
|
case "created_d1":
|
package/lib/families.js
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
import { GenericPage } from "./genericpage.js";
|
2
2
|
import { HTML } from "./html.js";
|
3
3
|
import { Jepson } from "./jepson.js";
|
4
|
-
import { Taxa } from "./taxa.js";
|
5
4
|
import { Files } from "./files.js";
|
6
5
|
import { Config } from "./config.js";
|
7
|
-
|
8
|
-
import { Taxon } from "./index.js";
|
6
|
+
import { HTMLTaxon } from "./htmltaxon.js";
|
9
7
|
|
10
8
|
class Family {
|
11
9
|
#name;
|
@@ -83,7 +81,7 @@ class Families {
|
|
83
81
|
|
84
82
|
/**
|
85
83
|
* @param {string} outputDir
|
86
|
-
* @param {
|
84
|
+
* @param {TaxaCol[]} taxaColumns
|
87
85
|
*/
|
88
86
|
renderPages(outputDir, taxaColumns) {
|
89
87
|
new PageFamilyList(outputDir, this.#families).render(taxaColumns);
|
@@ -111,7 +109,7 @@ class PageFamilyList extends GenericPage {
|
|
111
109
|
}
|
112
110
|
|
113
111
|
/**
|
114
|
-
* @param {
|
112
|
+
* @param {TaxaCol[]} taxaColumns
|
115
113
|
*/
|
116
114
|
render(taxaColumns) {
|
117
115
|
let html = this.getDefaultIntro();
|
@@ -178,8 +176,7 @@ class PageFamily extends GenericPage {
|
|
178
176
|
}
|
179
177
|
|
180
178
|
/**
|
181
|
-
*
|
182
|
-
* @param {import("./index.js").TaxaCol[]} columns
|
179
|
+
* @param {TaxaCol[]} columns
|
183
180
|
*/
|
184
181
|
render(columns) {
|
185
182
|
let html = this.getDefaultIntro();
|
@@ -190,7 +187,7 @@ class PageFamily extends GenericPage {
|
|
190
187
|
{ class: "section" }
|
191
188
|
);
|
192
189
|
|
193
|
-
html +=
|
190
|
+
html += HTMLTaxon.getTaxaTable(this.#family.getTaxa(), columns);
|
194
191
|
|
195
192
|
this.writeFile(html);
|
196
193
|
}
|
@@ -209,17 +206,20 @@ class PageSection extends GenericPage {
|
|
209
206
|
this.#taxa = taxa;
|
210
207
|
}
|
211
208
|
|
209
|
+
/**
|
210
|
+
* @param {TaxaCol[]} [columns]
|
211
|
+
*/
|
212
212
|
render(columns) {
|
213
213
|
let html = this.getDefaultIntro();
|
214
214
|
|
215
|
-
html +=
|
215
|
+
html += HTMLTaxon.getTaxaTable(this.#taxa, columns);
|
216
216
|
|
217
217
|
this.writeFile(html);
|
218
218
|
}
|
219
219
|
}
|
220
220
|
|
221
221
|
class Sections {
|
222
|
-
/** @type {Object<string,Taxon[]} */
|
222
|
+
/** @type {Object<string,Taxon[]>} */
|
223
223
|
static #sections = {};
|
224
224
|
|
225
225
|
/**
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { TextUtils } from "./textutils.js";
|
2
|
+
|
3
|
+
class FlowerColor {
|
4
|
+
#colorName;
|
5
|
+
#colorCode;
|
6
|
+
/** @type {Taxon[]} */
|
7
|
+
#taxa = [];
|
8
|
+
|
9
|
+
/**
|
10
|
+
* @param {string} colorName
|
11
|
+
* @param {string} [colorCode]
|
12
|
+
*/
|
13
|
+
constructor(colorName, colorCode) {
|
14
|
+
this.#colorName = colorName;
|
15
|
+
this.#colorCode = colorCode ? colorCode : colorName;
|
16
|
+
}
|
17
|
+
|
18
|
+
/**
|
19
|
+
* @param {Taxon} taxon
|
20
|
+
*/
|
21
|
+
addTaxon(taxon) {
|
22
|
+
this.#taxa.push(taxon);
|
23
|
+
}
|
24
|
+
|
25
|
+
getColorCode() {
|
26
|
+
return this.#colorCode;
|
27
|
+
}
|
28
|
+
|
29
|
+
getColorName(uc = false) {
|
30
|
+
return uc ? TextUtils.ucFirst(this.#colorName) : this.#colorName;
|
31
|
+
}
|
32
|
+
|
33
|
+
getFileName() {
|
34
|
+
return "list_fc_" + this.#colorName + ".html";
|
35
|
+
}
|
36
|
+
|
37
|
+
getTaxa() {
|
38
|
+
return this.#taxa;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
export { FlowerColor };
|
package/lib/genera.js
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
import { Config } from "./config.js";
|
2
|
-
import { Families } from "./families.js";
|
3
2
|
import { Files } from "./files.js";
|
4
|
-
// eslint-disable-next-line no-unused-vars
|
5
|
-
import { Taxon } from "./taxon.js";
|
6
3
|
|
7
4
|
class Genera {
|
8
5
|
#families;
|
@@ -24,21 +21,17 @@ class Genera {
|
|
24
21
|
const genusName = taxon.getGenusName();
|
25
22
|
const genusData = this.#genera[genusName];
|
26
23
|
if (!genusData) {
|
27
|
-
|
28
|
-
return;
|
24
|
+
throw new Error(taxon.getName() + " genus not found");
|
29
25
|
}
|
30
26
|
|
31
|
-
if (genusData.
|
27
|
+
if (genusData.familyObj === undefined) {
|
28
|
+
// Initialize genus data.
|
29
|
+
genusData.familyObj = this.#families.getFamily(genusData.family);
|
32
30
|
genusData.taxa = [];
|
33
31
|
}
|
34
|
-
genusData.
|
32
|
+
genusData.familyObj.addTaxon(taxon);
|
35
33
|
|
36
|
-
|
37
|
-
if (!family) {
|
38
|
-
console.log(taxon.getName() + " family not found");
|
39
|
-
return;
|
40
|
-
}
|
41
|
-
family.addTaxon(taxon);
|
34
|
+
genusData.taxa.push(taxon);
|
42
35
|
}
|
43
36
|
|
44
37
|
/**
|
@@ -47,25 +40,22 @@ class Genera {
|
|
47
40
|
getGenus(genusName) {
|
48
41
|
return new Genus(this.#genera[genusName]);
|
49
42
|
}
|
50
|
-
|
51
|
-
/**
|
52
|
-
* @param {string} genusName
|
53
|
-
*/
|
54
|
-
getFamily(genusName) {
|
55
|
-
const genus = this.#genera[genusName];
|
56
|
-
if (genus) {
|
57
|
-
return this.#families.getFamily(genus.family);
|
58
|
-
}
|
59
|
-
}
|
60
43
|
}
|
61
44
|
|
62
45
|
class Genus {
|
63
46
|
#data;
|
64
47
|
|
48
|
+
/**
|
49
|
+
* @param {{family:string,familyObj:Family,taxa:Taxon[]}} data
|
50
|
+
*/
|
65
51
|
constructor(data) {
|
66
52
|
this.#data = data;
|
67
53
|
}
|
68
54
|
|
55
|
+
getFamily() {
|
56
|
+
return this.#data.familyObj;
|
57
|
+
}
|
58
|
+
|
69
59
|
getTaxa() {
|
70
60
|
return this.#data.taxa.sort((a, b) =>
|
71
61
|
a.getName().localeCompare(b.getName())
|
package/lib/genericpage.js
CHANGED
@@ -1,14 +1,22 @@
|
|
1
|
-
import { Config
|
1
|
+
import { Config } from "./config.js";
|
2
|
+
import { Files } from "./files.js";
|
3
|
+
import { HTML } from "./html.js";
|
4
|
+
import { Jekyll } from "./jekyll.js";
|
2
5
|
import { Markdown } from "./markdown.js";
|
3
6
|
|
4
7
|
class GenericPage {
|
5
|
-
|
6
8
|
#outputDir;
|
7
9
|
#title;
|
8
10
|
#baseFileName;
|
9
11
|
#js;
|
10
12
|
|
11
|
-
|
13
|
+
/**
|
14
|
+
* @param {string} outputDir
|
15
|
+
* @param {string} title
|
16
|
+
* @param {string} baseFileName
|
17
|
+
* @param {string} [js]
|
18
|
+
*/
|
19
|
+
constructor(outputDir, title, baseFileName, js) {
|
12
20
|
this.#outputDir = outputDir;
|
13
21
|
this.#title = title;
|
14
22
|
this.#baseFileName = baseFileName;
|
@@ -25,31 +33,41 @@ class GenericPage {
|
|
25
33
|
}
|
26
34
|
|
27
35
|
getFrontMatter() {
|
28
|
-
return
|
29
|
-
|
30
|
-
|
31
|
-
+
|
36
|
+
return (
|
37
|
+
"---\n" +
|
38
|
+
'title: "' +
|
39
|
+
this.#title +
|
40
|
+
'"\n' +
|
41
|
+
(this.#js ? "js: " + this.#js + "\n" : "") +
|
42
|
+
"---\n"
|
43
|
+
);
|
32
44
|
}
|
33
45
|
|
34
46
|
getMarkdown() {
|
35
47
|
// Include site-specific markdown.
|
36
|
-
let html = this.#getMarkdown(
|
48
|
+
let html = this.#getMarkdown("intros");
|
37
49
|
|
38
50
|
// Include package markdown.
|
39
|
-
const mdPath =
|
40
|
-
|
41
|
-
|
51
|
+
const mdPath =
|
52
|
+
Config.getPackageDir() + "/data/text/" + this.#baseFileName + ".md";
|
53
|
+
if (Files.exists(mdPath)) {
|
54
|
+
html += HTML.wrap("div", Markdown.fileToHTML(mdPath), {
|
55
|
+
class: "section",
|
56
|
+
});
|
42
57
|
}
|
43
58
|
|
44
59
|
return html;
|
45
60
|
}
|
46
61
|
|
47
|
-
|
62
|
+
/**
|
63
|
+
* @param {string} path
|
64
|
+
*/
|
65
|
+
#getMarkdown(path) {
|
48
66
|
const textPath = path + "/" + this.#baseFileName + ".md";
|
49
|
-
if (
|
67
|
+
if (!Jekyll.hasInclude(this.#outputDir, textPath)) {
|
50
68
|
return "";
|
51
69
|
}
|
52
|
-
return HTML.wrap(
|
70
|
+
return HTML.wrap("div", Jekyll.include(textPath), { class: "section" });
|
53
71
|
}
|
54
72
|
|
55
73
|
getOutputDir() {
|
@@ -60,10 +78,12 @@ class GenericPage {
|
|
60
78
|
return this.#title;
|
61
79
|
}
|
62
80
|
|
63
|
-
|
64
|
-
|
81
|
+
/**
|
82
|
+
* @param {string} html
|
83
|
+
*/
|
84
|
+
writeFile(html) {
|
85
|
+
Files.write(this.#outputDir + "/" + this.#baseFileName + ".html", html);
|
65
86
|
}
|
66
|
-
|
67
87
|
}
|
68
88
|
|
69
|
-
export { GenericPage };
|
89
|
+
export { GenericPage };
|
package/lib/html.js
CHANGED
@@ -1,11 +1,3 @@
|
|
1
|
-
/**
|
2
|
-
* @deprecated
|
3
|
-
*/
|
4
|
-
export const HTML_OPTIONS = {
|
5
|
-
OPEN_NEW: 1,
|
6
|
-
NO_ESCAPE: 2,
|
7
|
-
};
|
8
|
-
|
9
1
|
/** HTML utility functions. */
|
10
2
|
export class HTML {
|
11
3
|
/**
|
@@ -35,19 +27,6 @@ export class HTML {
|
|
35
27
|
.replaceAll(">", ">");
|
36
28
|
}
|
37
29
|
|
38
|
-
/**
|
39
|
-
* @deprecated
|
40
|
-
*/
|
41
|
-
static getElement(elName, text, attributes = {}, options = 0) {
|
42
|
-
let html = "<" + elName;
|
43
|
-
html += this.renderAttributes(attributes);
|
44
|
-
if (!(options & HTML_OPTIONS.NO_ESCAPE)) {
|
45
|
-
text = this.escapeText(text);
|
46
|
-
}
|
47
|
-
html += ">" + text + "</" + elName + ">";
|
48
|
-
return html;
|
49
|
-
}
|
50
|
-
|
51
30
|
/**
|
52
31
|
* @param {string} elName
|
53
32
|
* @param {string} text
|
@@ -71,7 +50,7 @@ export class HTML {
|
|
71
50
|
* Generate HTML for an <a> element.
|
72
51
|
* @param {string|undefined} href
|
73
52
|
* @param {string} linkText
|
74
|
-
* @param {Object} [attributes]
|
53
|
+
* @param {string|Object<string,string>} [attributes]
|
75
54
|
* @param {boolean} [openInNewWindow] true if the link should open in a new window.
|
76
55
|
* @returns {string} an HTML <a> element.
|
77
56
|
*/
|
@@ -92,7 +71,7 @@ export class HTML {
|
|
92
71
|
* @param {string} text - The text or HTML that should trigger the tooltip on hover.
|
93
72
|
* @param {string} tooltip - The tooltip text or HTML.
|
94
73
|
* @param {Object} options
|
95
|
-
* @param {boolean} options.icon [true] display an icon after the text
|
74
|
+
* @param {boolean} [options.icon] [true] display an icon after the text
|
96
75
|
* @returns {string} A <span> element to be used as a Bootstrap tooltip.
|
97
76
|
*/
|
98
77
|
static getToolTip(text, tooltip, options = {}) {
|
@@ -103,6 +82,10 @@ export class HTML {
|
|
103
82
|
return func("span", text, { "data-bs-html": "true", title: tooltip });
|
104
83
|
}
|
105
84
|
|
85
|
+
/**
|
86
|
+
* @param {string} n
|
87
|
+
* @param {string} v
|
88
|
+
*/
|
106
89
|
static renderAttribute(n, v) {
|
107
90
|
return " " + n + '="' + this.escapeAttribute(v) + '"';
|
108
91
|
}
|
@@ -121,6 +104,11 @@ export class HTML {
|
|
121
104
|
return html;
|
122
105
|
}
|
123
106
|
|
107
|
+
/**
|
108
|
+
* @param {string} elName
|
109
|
+
* @param {string} text
|
110
|
+
* @param {Object<string,string>} attributes
|
111
|
+
*/
|
124
112
|
static textElement(elName, text, attributes = {}) {
|
125
113
|
return HTML.#getElement(elName, text, attributes, true);
|
126
114
|
}
|
package/lib/htmltaxon.js
CHANGED
@@ -1,15 +1,83 @@
|
|
1
1
|
import { DateUtils } from "./dateutils.js";
|
2
2
|
import { HTML } from "./html.js";
|
3
|
-
|
4
|
-
import { Taxon } from "./taxon.js";
|
3
|
+
import { RarePlants } from "./rareplants.js";
|
5
4
|
import { TextUtils } from "./textutils.js";
|
6
5
|
|
6
|
+
/**
|
7
|
+
* @type {Object<string,{title:string,data:function (Taxon):string}>}
|
8
|
+
*/
|
9
|
+
const TAXA_LIST_COLS = {
|
10
|
+
CESA: {
|
11
|
+
title: "California",
|
12
|
+
data: (t) => RarePlants.getCESADescription(t.getCESA()),
|
13
|
+
},
|
14
|
+
COMMON_NAME: {
|
15
|
+
title: "Common Name",
|
16
|
+
data: (t) => t.getCommonNames().join(", "),
|
17
|
+
},
|
18
|
+
CNPS_RANK: {
|
19
|
+
title: "CNPS Rank",
|
20
|
+
data: (t) =>
|
21
|
+
HTML.getToolTip(
|
22
|
+
HTML.textElement("span", t.getRPIRankAndThreat()),
|
23
|
+
t.getRPIRankAndThreatTooltip()
|
24
|
+
),
|
25
|
+
},
|
26
|
+
FESA: {
|
27
|
+
title: "Federal",
|
28
|
+
data: (t) => RarePlants.getFESADescription(t.getFESA()),
|
29
|
+
},
|
30
|
+
SPECIES: {
|
31
|
+
title: "Species",
|
32
|
+
data: (t) => t.getHTMLLink(true, true),
|
33
|
+
},
|
34
|
+
SPECIES_BARE: {
|
35
|
+
title: "Species",
|
36
|
+
data: (t) => t.getHTMLLink(true, false),
|
37
|
+
},
|
38
|
+
};
|
39
|
+
|
40
|
+
const DEFAULT_TAXA_COLUMNS = [
|
41
|
+
TAXA_LIST_COLS.SPECIES,
|
42
|
+
TAXA_LIST_COLS.COMMON_NAME,
|
43
|
+
];
|
44
|
+
|
7
45
|
class HTMLTaxon {
|
46
|
+
/**
|
47
|
+
* @param {string[]|undefined} colors
|
48
|
+
*/
|
49
|
+
static getFlowerColors(colors, includeColorLink = true) {
|
50
|
+
let html = "";
|
51
|
+
if (colors) {
|
52
|
+
for (const color of colors) {
|
53
|
+
const img = HTML.textElement("img", "", {
|
54
|
+
src: "./i/f-" + color + ".svg",
|
55
|
+
alt: color + " flowers",
|
56
|
+
title: color,
|
57
|
+
class: "flr-color",
|
58
|
+
});
|
59
|
+
if (includeColorLink) {
|
60
|
+
html += HTML.wrap("a", img, {
|
61
|
+
href: "./list_fc_" + color + ".html",
|
62
|
+
});
|
63
|
+
} else {
|
64
|
+
html += img;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
return html;
|
69
|
+
}
|
70
|
+
|
8
71
|
/**
|
9
72
|
* @param {Taxon} taxon
|
10
73
|
* @param {string} classNames
|
74
|
+
* @param {boolean} [includeColorLink=true]
|
11
75
|
*/
|
12
|
-
static getFlowerInfo(
|
76
|
+
static getFlowerInfo(
|
77
|
+
taxon,
|
78
|
+
classNames = "section",
|
79
|
+
includeColorLink = true
|
80
|
+
) {
|
13
81
|
const lifeCycle = taxon.getLifeCycle();
|
14
82
|
const colors = taxon.getFlowerColors();
|
15
83
|
const monthStart = taxon.getBloomStart();
|
@@ -24,16 +92,7 @@ class HTMLTaxon {
|
|
24
92
|
|
25
93
|
if (colors || monthStart) {
|
26
94
|
let html = "Flowers: ";
|
27
|
-
|
28
|
-
for (const color of colors) {
|
29
|
-
html += HTML.textElement("img", "", {
|
30
|
-
src: "./i/f-" + color + ".svg",
|
31
|
-
alt: color + " flowers",
|
32
|
-
title: color,
|
33
|
-
class: "flr-color",
|
34
|
-
});
|
35
|
-
}
|
36
|
-
}
|
95
|
+
html += this.getFlowerColors(colors, includeColorLink);
|
37
96
|
if (monthStart && monthEnd) {
|
38
97
|
html += HTML.wrap(
|
39
98
|
"span",
|
@@ -47,6 +106,47 @@ class HTMLTaxon {
|
|
47
106
|
}
|
48
107
|
return HTML.wrap("div", parts.join(""), { class: classNames });
|
49
108
|
}
|
109
|
+
|
110
|
+
/**
|
111
|
+
* @param {Taxon} taxon
|
112
|
+
*/
|
113
|
+
static getLink(taxon) {
|
114
|
+
return (
|
115
|
+
HTML.getLink(taxon.getFileName(), taxon.getName()) +
|
116
|
+
this.getFlowerColors(taxon.getFlowerColors())
|
117
|
+
);
|
118
|
+
}
|
119
|
+
|
120
|
+
/**
|
121
|
+
* @param {Taxon[]} taxa
|
122
|
+
* @param {TaxaCol[]} [columns]
|
123
|
+
*/
|
124
|
+
static getTaxaTable(taxa, columns = DEFAULT_TAXA_COLUMNS) {
|
125
|
+
let html = "<table><thead>";
|
126
|
+
for (const col of columns) {
|
127
|
+
const className = col.class;
|
128
|
+
const atts = className !== undefined ? className : {};
|
129
|
+
html += HTML.textElement("th", col.title, atts);
|
130
|
+
}
|
131
|
+
html += "</thead>";
|
132
|
+
html += "<tbody>";
|
133
|
+
|
134
|
+
for (const taxon of taxa) {
|
135
|
+
html += "<tr>";
|
136
|
+
for (const col of columns) {
|
137
|
+
const data = col.data(taxon);
|
138
|
+
const className = col.class;
|
139
|
+
const atts = className !== undefined ? className : {};
|
140
|
+
html += HTML.wrap("td", data, atts);
|
141
|
+
}
|
142
|
+
html += "</tr>";
|
143
|
+
}
|
144
|
+
|
145
|
+
html += "</tbody>";
|
146
|
+
html += "</table>";
|
147
|
+
|
148
|
+
return html;
|
149
|
+
}
|
50
150
|
}
|
51
151
|
|
52
|
-
export { HTMLTaxon };
|
152
|
+
export { HTMLTaxon, TAXA_LIST_COLS };
|
package/lib/index.d.ts
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
import { Command } from "commander";
|
2
|
+
|
3
|
+
export class Config {
|
4
|
+
constructor(dataDir: string);
|
5
|
+
getConfigValue(
|
6
|
+
prefix: string,
|
7
|
+
name: string,
|
8
|
+
subcategory?: string,
|
9
|
+
defaultValue?: string
|
10
|
+
): string;
|
11
|
+
getCountyCodes(): string[];
|
12
|
+
getLabel(name: string, dflt: string): string;
|
13
|
+
}
|
14
|
+
|
15
|
+
export class CSV {
|
16
|
+
static parseFile(dir: string, fileName: string);
|
17
|
+
}
|
18
|
+
|
19
|
+
export class ErrorLog {
|
20
|
+
constructor(fileName: string, echo?: boolean);
|
21
|
+
log(...msg: string[]);
|
22
|
+
write(): void;
|
23
|
+
}
|
24
|
+
|
25
|
+
export class Exceptions {
|
26
|
+
constructor(dataDir: string);
|
27
|
+
hasException(name: string, cat: string, subcat: string);
|
28
|
+
}
|
29
|
+
|
30
|
+
export class Files {
|
31
|
+
static exists(fileName: string): boolean;
|
32
|
+
static async fetch(url: string | URL, targetFileName: string | undefined);
|
33
|
+
static mkdir(dir: string);
|
34
|
+
static rmDir(dir: string);
|
35
|
+
static write(fileName: string, data: string, overwrite: boolean);
|
36
|
+
}
|
37
|
+
|
38
|
+
export class Program {
|
39
|
+
static getIncludeList(dataDir: string): string[];
|
40
|
+
static getProgram(): Command;
|
41
|
+
}
|
42
|
+
|
43
|
+
export class Taxa {
|
44
|
+
constructor(
|
45
|
+
inclusionList: Object<string, TaxonData> | true,
|
46
|
+
errorLog: ErrorLog,
|
47
|
+
showFlowerErrors: boolean,
|
48
|
+
taxonFactory?: (td: TaxonData, g: Genera) => Taxon,
|
49
|
+
extraTaxa?: TaxonData[],
|
50
|
+
extraSynonyms?: SynonymData[]
|
51
|
+
);
|
52
|
+
getTaxon(string): Taxon;
|
53
|
+
getTaxonList(): Taxon[];
|
54
|
+
}
|