@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.
@@ -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( func ) {
9
+ static #debounce( timeout = 500 ) {
10
10
  clearTimeout( this.#debounceTimer );
11
- this.#debounceTimer = setTimeout( func, 500 );
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( Search.#doSearch );
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
  }
@@ -8,7 +8,7 @@ js: name_search.js
8
8
  const NAMES = {% include names.json%};
9
9
  </script>
10
10
 
11
- <form>
11
+ <form id="search_form">
12
12
  <input type="text" id="name"><label for="name">Search for scientific name, common name, or synonym</label>
13
13
  </form>
14
14
 
@@ -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: 300 } );
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, HTML_OPTIONS } from "./html.js";
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.getElement( "h1", title );
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.getElement( "h1", this.#family.getName() );
78
+ html += HTML.textElement( "h1", this.#family.getName() );
79
79
 
80
- html += HTML.getElement(
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( "&", "&amp;" ).replaceAll( "<", "&lt;" ).replaceAll( ">", "&gt;" );
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 };
@@ -1,13 +1,15 @@
1
1
  import * as fs from "node:fs";
2
- import { Families } from "./families.js";
3
- import { HTML, HTML_OPTIONS } from "./html.js";
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
- new PageTaxonList().render( outputDir, taxa, list.filename, list.name );
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.getElement( "ul", HTML.arrayToLI( listsHTML ), attributes, HTML_OPTIONS.NO_ESCAPE );
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.getElement( "h2", title );
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.getElement( "h1", title );
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.getElement( "h2", "Download" );
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=\"wrapper\">";
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, HTML_OPTIONS } from "./html.js";
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
- html += HTML.getElement( "th", "Species" );
14
- html += HTML.getElement( "th", "Common Name" );
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
- html += HTML.getElement(
21
- "td",
22
- taxon.getHTMLLink(),
23
- undefined,
24
- HTML_OPTIONS.NO_ESCAPE
25
- );
26
- html += HTML.getElement( "td", taxon.getCommonNames().join( ", " ) );
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
- const className = this.isNative() ? ( this.isRare() ? "rare" : "native" ) : "non-native";
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
- attributes[ "title" ] = RarePlants.getRPIRankAndThreatDescriptions( this.getRPIRankAndThreat() ).join( "\n" );
111
+ this.getRPIRankAndThreatTooltip( attributes );
109
112
  }
110
- return HTML.getElement( "span", HTML.getLink( href, this.getName() ), attributes, HTML_OPTIONS.NO_ESCAPE );
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 ) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ca-plant-list/ca-plant-list",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Tools to create Jekyll files for a website listing plants in an area of California.",
5
5
  "license": "MIT",
6
6
  "repository": {