@ca-plant-list/ca-plant-list 0.1.5 → 0.1.7
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/jekyll/assets/css/main.css +9 -0
- package/jekyll/assets/js/name_search.js +8 -3
- package/jekyll/name_search.html +1 -1
- package/lib/basepagerenderer.js +4 -1
- package/lib/families.js +5 -6
- package/lib/html.js +24 -0
- package/lib/pagerenderer.js +20 -15
- package/lib/pagetaxon.js +1 -1
- package/lib/taxa.js +39 -12
- package/lib/taxon.js +12 -4
- package/package.json +1 -1
@@ -61,6 +61,13 @@ span.rare::before {
|
|
61
61
|
font-weight: 600;
|
62
62
|
}
|
63
63
|
|
64
|
+
div.grid {
|
65
|
+
display: grid;
|
66
|
+
grid-auto-flow: row;
|
67
|
+
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
|
68
|
+
column-gap: 2rem;
|
69
|
+
}
|
70
|
+
|
64
71
|
div.wrapper {
|
65
72
|
display: flex;
|
66
73
|
flex-wrap: wrap;
|
@@ -82,6 +89,8 @@ div.section ul {
|
|
82
89
|
|
83
90
|
div.section li {
|
84
91
|
display: block;
|
92
|
+
margin-left: 1rem;
|
93
|
+
text-indent: -1rem;
|
85
94
|
}
|
86
95
|
|
87
96
|
div.section ul.indent {
|
@@ -6,9 +6,9 @@ class Search {
|
|
6
6
|
static #debounceTimer;
|
7
7
|
static #searchData;
|
8
8
|
|
9
|
-
static #debounce(
|
9
|
+
static #debounce( timeout = 500 ) {
|
10
10
|
clearTimeout( this.#debounceTimer );
|
11
|
-
this.#debounceTimer = setTimeout(
|
11
|
+
this.#debounceTimer = setTimeout( Search.#doSearch, timeout );
|
12
12
|
}
|
13
13
|
|
14
14
|
static #doSearch() {
|
@@ -141,7 +141,11 @@ class Search {
|
|
141
141
|
}
|
142
142
|
|
143
143
|
static #handleChange() {
|
144
|
-
this.#debounce(
|
144
|
+
this.#debounce();
|
145
|
+
}
|
146
|
+
|
147
|
+
static #handleSubmit() {
|
148
|
+
this.#debounce( 0 );
|
145
149
|
}
|
146
150
|
|
147
151
|
static init() {
|
@@ -149,6 +153,7 @@ class Search {
|
|
149
153
|
const eName = document.getElementById( "name" );
|
150
154
|
eName.focus();
|
151
155
|
eName.oninput = ( ev ) => { return this.#handleChange( ev ); };
|
156
|
+
document.getElementById( "search_form" ).onsubmit = () => { this.#handleSubmit(); return false; };
|
152
157
|
}
|
153
158
|
|
154
159
|
}
|
package/jekyll/name_search.html
CHANGED
package/lib/basepagerenderer.js
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
import * as fs from "node:fs";
|
2
2
|
import { Config } from "./config.js";
|
3
|
+
import { Families } from "./families.js";
|
3
4
|
|
4
5
|
class BasePageRenderer {
|
5
6
|
|
6
7
|
static render( outputDir, Taxa ) {
|
7
8
|
|
8
9
|
// Copy static files
|
9
|
-
fs.rmSync( outputDir, { force: true, recursive: true, maxRetries: 2, retryDelay:
|
10
|
+
fs.rmSync( outputDir, { force: true, recursive: true, maxRetries: 2, retryDelay: 400 } );
|
10
11
|
// First copy default Jekyll files from package.
|
11
12
|
fs.cpSync( Config.getPackageDir() + "/jekyll", outputDir, { recursive: true } );
|
12
13
|
// Then copy Jekyll files from current dir (which may override default files).
|
13
14
|
fs.cpSync( "jekyll", outputDir, { recursive: true } );
|
14
15
|
|
16
|
+
Families.renderPages( outputDir );
|
17
|
+
|
15
18
|
this.renderTools( outputDir, Taxa );
|
16
19
|
|
17
20
|
}
|
package/lib/families.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import * as fs from "node:fs";
|
2
2
|
import { HTMLPage } from "./htmlpage.js";
|
3
|
-
import { HTML
|
3
|
+
import { HTML } from "./html.js";
|
4
4
|
import { Jepson } from "./jepson.js";
|
5
5
|
import { Taxa } from "./taxa.js";
|
6
6
|
|
@@ -46,7 +46,7 @@ class PageFamilyList extends HTMLPage {
|
|
46
46
|
|
47
47
|
let html = this.getFrontMatter( title );
|
48
48
|
|
49
|
-
html += HTML.
|
49
|
+
html += HTML.textElement( "h1", title );
|
50
50
|
|
51
51
|
html += "<ul>";
|
52
52
|
for ( const family of this.#families ) {
|
@@ -75,13 +75,12 @@ class PageFamily extends HTMLPage {
|
|
75
75
|
|
76
76
|
let html = this.getFrontMatter( this.#family.getName() );
|
77
77
|
|
78
|
-
html += HTML.
|
78
|
+
html += HTML.textElement( "h1", this.#family.getName() );
|
79
79
|
|
80
|
-
html += HTML.
|
80
|
+
html += HTML.wrap(
|
81
81
|
"div",
|
82
82
|
Jepson.getEFloraLink( this.#family.getJepsonID() ),
|
83
|
-
{ class: "section" }
|
84
|
-
HTML_OPTIONS.NO_ESCAPE
|
83
|
+
{ class: "section" }
|
85
84
|
);
|
86
85
|
|
87
86
|
html += Taxa.getHTMLTable( this.#family.getTaxa() );
|
package/lib/html.js
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
/**
|
2
|
+
* @deprecated
|
3
|
+
*/
|
1
4
|
const HTML_OPTIONS = {
|
2
5
|
OPEN_NEW: 1,
|
3
6
|
NO_ESCAPE: 2,
|
@@ -17,6 +20,9 @@ class HTML {
|
|
17
20
|
return text.replaceAll( "&", "&" ).replaceAll( "<", "<" ).replaceAll( ">", ">" );
|
18
21
|
}
|
19
22
|
|
23
|
+
/**
|
24
|
+
* @deprecated
|
25
|
+
*/
|
20
26
|
static getElement( elName, text, attributes = {}, options = 0 ) {
|
21
27
|
let html = "<" + elName;
|
22
28
|
html += this.renderAttributes( attributes );
|
@@ -28,6 +34,16 @@ class HTML {
|
|
28
34
|
|
29
35
|
}
|
30
36
|
|
37
|
+
static #getElement( elName, text, attributes, escape ) {
|
38
|
+
let html = "<" + elName;
|
39
|
+
html += this.renderAttributes( attributes );
|
40
|
+
if ( escape ) {
|
41
|
+
text = this.escapeText( text );
|
42
|
+
}
|
43
|
+
html += ">" + text + "</" + elName + ">";
|
44
|
+
return html;
|
45
|
+
}
|
46
|
+
|
31
47
|
static getLink( href, linkText, attributes = {}, options = 0 ) {
|
32
48
|
let html = "<a";
|
33
49
|
if ( href !== undefined ) {
|
@@ -52,6 +68,14 @@ class HTML {
|
|
52
68
|
return html;
|
53
69
|
}
|
54
70
|
|
71
|
+
static textElement( elName, text, attributes = {} ) {
|
72
|
+
return this.#getElement( elName, text, attributes, true );
|
73
|
+
}
|
74
|
+
|
75
|
+
static wrap( elName, text, attributes = {} ) {
|
76
|
+
return this.#getElement( elName, text, attributes, false );
|
77
|
+
}
|
78
|
+
|
55
79
|
}
|
56
80
|
|
57
81
|
export { HTML, HTML_OPTIONS };
|
package/lib/pagerenderer.js
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
import * as fs from "node:fs";
|
2
|
-
import {
|
3
|
-
import {
|
4
|
-
import { Taxa } from "./taxa.js";
|
2
|
+
import { HTML } from "./html.js";
|
3
|
+
import { Taxa, COLUMNS } from "./taxa.js";
|
5
4
|
import { HTMLPage } from "./htmlpage.js";
|
6
5
|
import { PageTaxon } from "./pagetaxon.js";
|
7
6
|
import { Config } from "./config.js";
|
8
7
|
import { RarePlants } from "./rareplants.js";
|
9
8
|
import { BasePageRenderer } from "./basepagerenderer.js";
|
10
9
|
|
10
|
+
const RPI_CESA = [ COLUMNS.COL_SPECIES, COLUMNS.COL_COMMON_NAME, COLUMNS.COL_CESA ];
|
11
|
+
const RPI_COLUMNS = [ COLUMNS.COL_SPECIES, COLUMNS.COL_COMMON_NAME, COLUMNS.COL_CNPS_RANK ];
|
12
|
+
|
11
13
|
class PageRenderer extends BasePageRenderer {
|
12
14
|
|
13
15
|
static render( outputDir ) {
|
@@ -16,8 +18,6 @@ class PageRenderer extends BasePageRenderer {
|
|
16
18
|
|
17
19
|
this.renderLists( outputDir );
|
18
20
|
|
19
|
-
Families.renderPages( outputDir );
|
20
|
-
|
21
21
|
const taxa = Taxa.getTaxa();
|
22
22
|
for ( const taxon of taxa ) {
|
23
23
|
new PageTaxon( taxon ).render( outputDir );
|
@@ -27,7 +27,8 @@ class PageRenderer extends BasePageRenderer {
|
|
27
27
|
|
28
28
|
static renderLists( outputDir ) {
|
29
29
|
|
30
|
-
function getListArray( listInfo, attributes = {} ) {
|
30
|
+
function getListArray( listInfo, attributes = {}, columns ) {
|
31
|
+
|
31
32
|
const listArray = [];
|
32
33
|
for ( const list of listInfo ) {
|
33
34
|
const taxa = [];
|
@@ -48,23 +49,25 @@ class PageRenderer extends BasePageRenderer {
|
|
48
49
|
fs.writeFileSync( outputDir + "/calflora_" + list.filename + ".txt", calfloraTaxa.join( "\n" ) );
|
49
50
|
fs.writeFileSync( outputDir + "/inat_" + list.filename + ".txt", iNatTaxa.join( "\n" ) );
|
50
51
|
|
51
|
-
|
52
|
+
const cols = columns ? columns : list.columns;
|
53
|
+
new PageTaxonList().render( outputDir, taxa, list.filename, list.name, cols );
|
52
54
|
|
53
55
|
// Check for sublists.
|
54
|
-
const subListHTML = list.listInfo ? getListArray( list.listInfo, { class: "indent" } ) : "";
|
56
|
+
const subListHTML = list.listInfo ? getListArray( list.listInfo, { class: "indent" }, cols ) : "";
|
55
57
|
|
56
58
|
listArray.push( HTML.getLink( "./" + list.filename + ".html", list.name ) + " (" + taxa.length + ")" + subListHTML );
|
57
59
|
}
|
60
|
+
|
58
61
|
return renderList( listArray, attributes );
|
59
62
|
}
|
60
63
|
|
61
64
|
function renderList( listsHTML, attributes = {} ) {
|
62
|
-
return HTML.
|
65
|
+
return HTML.wrap( "ul", HTML.arrayToLI( listsHTML ), attributes );
|
63
66
|
}
|
64
67
|
|
65
68
|
function renderSection( title, listsHTML ) {
|
66
69
|
let html = "<div class=\"section\">";
|
67
|
-
html += HTML.
|
70
|
+
html += HTML.textElement( "h2", title );
|
68
71
|
html += listsHTML;
|
69
72
|
html += "</div>";
|
70
73
|
return html;
|
@@ -86,6 +89,7 @@ class PageRenderer extends BasePageRenderer {
|
|
86
89
|
name: "CNPS Ranked Plants",
|
87
90
|
filename: "list_rpi",
|
88
91
|
include: ( t ) => t.getRPIRank() !== undefined,
|
92
|
+
columns: RPI_COLUMNS,
|
89
93
|
listInfo: [
|
90
94
|
{
|
91
95
|
name: RarePlants.getRPIRankDescription( "1A" ),
|
@@ -123,6 +127,7 @@ class PageRenderer extends BasePageRenderer {
|
|
123
127
|
name: "California Endangered Species Act",
|
124
128
|
filename: "list_cesa",
|
125
129
|
include: ( t ) => t.getCESA() !== undefined,
|
130
|
+
columns: RPI_CESA,
|
126
131
|
listInfo: [
|
127
132
|
{
|
128
133
|
name: RarePlants.getCESADescription( "CE" ),
|
@@ -153,7 +158,7 @@ class PageRenderer extends BasePageRenderer {
|
|
153
158
|
let html = "<div class=\"wrapper\">";
|
154
159
|
for ( const section of sections ) {
|
155
160
|
|
156
|
-
const listHTML = getListArray( section.listInfo );
|
161
|
+
const listHTML = getListArray( section.listInfo, section.listInfo.columns );
|
157
162
|
|
158
163
|
if ( listHTML.length > 0 ) {
|
159
164
|
html += renderSection( section.title, listHTML );
|
@@ -173,20 +178,20 @@ class PageRenderer extends BasePageRenderer {
|
|
173
178
|
|
174
179
|
class PageTaxonList extends HTMLPage {
|
175
180
|
|
176
|
-
render( outputDir, taxa, baseName, title ) {
|
181
|
+
render( outputDir, taxa, baseName, title, columns ) {
|
177
182
|
|
178
183
|
let html = this.getFrontMatter( title );
|
179
184
|
|
180
|
-
html += HTML.
|
185
|
+
html += HTML.textElement( "h1", title );
|
181
186
|
|
182
187
|
html += "<div class=\"wrapper\">";
|
183
188
|
|
184
189
|
html += "<div class=\"section\">";
|
185
|
-
html += Taxa.getHTMLTable( taxa );
|
190
|
+
html += Taxa.getHTMLTable( taxa, columns );
|
186
191
|
html += "</div>";
|
187
192
|
|
188
193
|
html += "<div class=\"section\">";
|
189
|
-
html += HTML.
|
194
|
+
html += HTML.textElement( "h2", "Download" );
|
190
195
|
html += "<ul>";
|
191
196
|
html += "<li>" + HTML.getLink( "./calflora_" + baseName + ".txt", "Calflora List" ) + "</li>";
|
192
197
|
html += "<li>" + HTML.getLink( "./inat_" + baseName + ".txt", "iNaturalist List" ) + "</li>";
|
package/lib/pagetaxon.js
CHANGED
@@ -151,7 +151,7 @@ class PageTaxon extends HTMLPage {
|
|
151
151
|
);
|
152
152
|
}
|
153
153
|
|
154
|
-
html += "<div class=\"
|
154
|
+
html += "<div class=\"grid\">";
|
155
155
|
html += this.#getListSectionHTML( this.#getInfoLinks(), "Information", "info" );
|
156
156
|
html += this.#getListSectionHTML( this.#getObsLinks(), "Observations", "obs" );
|
157
157
|
html += this.#getListSectionHTML( this.#getRelatedTaxaLinks(), "Related Species", "rel-taxa" );
|
package/lib/taxa.js
CHANGED
@@ -1,29 +1,56 @@
|
|
1
1
|
import { Taxon } from "./taxon.js";
|
2
2
|
import { ErrorLog } from "./errorlog.js";
|
3
|
-
import { HTML
|
3
|
+
import { HTML } from "./html.js";
|
4
4
|
import { CSV } from "./csv.js";
|
5
|
+
import { RarePlants } from "./rareplants.js";
|
6
|
+
|
7
|
+
const COLUMNS = {
|
8
|
+
COL_CESA: "CESA",
|
9
|
+
COL_COMMON_NAME: "Common Name",
|
10
|
+
COL_CNPS_RANK: "CNPS Rank",
|
11
|
+
COL_SPECIES: "Species",
|
12
|
+
};
|
13
|
+
|
14
|
+
const DEFAULT_COLUMNS = [ COLUMNS.COL_SPECIES, COLUMNS.COL_COMMON_NAME ];
|
5
15
|
|
6
16
|
class Taxa {
|
7
17
|
|
8
18
|
static #taxa = {};
|
9
19
|
static #sortedTaxa;
|
10
20
|
|
11
|
-
static getHTMLTable( taxa ) {
|
21
|
+
static getHTMLTable( taxa, columns = DEFAULT_COLUMNS ) {
|
22
|
+
|
23
|
+
let includeRPI = true;
|
24
|
+
|
12
25
|
let html = "<table><thead>";
|
13
|
-
|
14
|
-
|
26
|
+
for ( const column of columns ) {
|
27
|
+
html += HTML.textElement( "th", column );
|
28
|
+
if ( column === COLUMNS.COL_CNPS_RANK ) {
|
29
|
+
// Don't show rarity with species link if CNPS Rank column is included.
|
30
|
+
includeRPI = false;
|
31
|
+
}
|
32
|
+
}
|
15
33
|
html += "</thead>";
|
16
34
|
html += "<tbody>";
|
17
35
|
|
18
36
|
for ( const taxon of taxa ) {
|
19
37
|
html += "<tr>";
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
38
|
+
for ( const column of columns ) {
|
39
|
+
switch ( column ) {
|
40
|
+
case COLUMNS.COL_CESA:
|
41
|
+
html += HTML.textElement( "td", RarePlants.getCESADescription( taxon.getCESA() ) );
|
42
|
+
break;
|
43
|
+
case COLUMNS.COL_COMMON_NAME:
|
44
|
+
html += HTML.textElement( "td", taxon.getCommonNames().join( ", " ) );
|
45
|
+
break;
|
46
|
+
case COLUMNS.COL_CNPS_RANK:
|
47
|
+
html += HTML.wrap( "td", HTML.wrap( "span", taxon.getRPIRankAndThreat(), taxon.getRPIRankAndThreatTooltip( {} ) ) );
|
48
|
+
break;
|
49
|
+
case COLUMNS.COL_SPECIES:
|
50
|
+
html += HTML.wrap( "td", taxon.getHTMLLink( true, includeRPI ) );
|
51
|
+
break;
|
52
|
+
}
|
53
|
+
}
|
27
54
|
html += "</tr>";
|
28
55
|
}
|
29
56
|
|
@@ -93,4 +120,4 @@ class Taxa {
|
|
93
120
|
|
94
121
|
}
|
95
122
|
|
96
|
-
export { Taxa };
|
123
|
+
export { Taxa, COLUMNS };
|
package/lib/taxon.js
CHANGED
@@ -100,14 +100,17 @@ class Taxon {
|
|
100
100
|
return this.#genus;
|
101
101
|
}
|
102
102
|
|
103
|
-
getHTMLLink( href = true ) {
|
103
|
+
getHTMLLink( href = true, includeRPI = true ) {
|
104
104
|
href = href ? ( "./" + this.getFileName() ) : undefined;
|
105
|
-
|
105
|
+
let className = this.isNative() ? "native" : "non-native";
|
106
|
+
if ( includeRPI && this.isRare() ) {
|
107
|
+
className = "rare";
|
108
|
+
}
|
106
109
|
const attributes = { class: className };
|
107
110
|
if ( className === "rare" ) {
|
108
|
-
|
111
|
+
this.getRPIRankAndThreatTooltip( attributes );
|
109
112
|
}
|
110
|
-
return HTML.
|
113
|
+
return HTML.wrap( "span", HTML.getLink( href, this.getName() ), attributes );
|
111
114
|
}
|
112
115
|
|
113
116
|
getINatID() {
|
@@ -151,6 +154,11 @@ class Taxon {
|
|
151
154
|
return this.#rankRPI;
|
152
155
|
}
|
153
156
|
|
157
|
+
getRPIRankAndThreatTooltip( attributes ) {
|
158
|
+
attributes[ "title" ] = RarePlants.getRPIRankAndThreatDescriptions( this.getRPIRankAndThreat() ).join( "\n" );
|
159
|
+
return attributes;
|
160
|
+
}
|
161
|
+
|
154
162
|
getRPITaxonLink() {
|
155
163
|
const rpiID = this.getRPIID();
|
156
164
|
if ( !rpiID ) {
|