minor refactors
authorJustin Wind <justin.wind+git@gmail.com>
Fri, 22 Mar 2024 23:15:40 +0000 (16:15 -0700)
committerJustin Wind <justin.wind+git@gmail.com>
Fri, 22 Mar 2024 23:15:40 +0000 (16:15 -0700)
README.md
lib/template-helper.js
test/lib/template-helper.js

index 888bd544321116c86bff3f8a0b38db7716f84fa9..68f91ea85a20c2247666df5b4c20f1820cc03420 100644 (file)
--- a/README.md
+++ b/README.md
@@ -4,6 +4,8 @@ Simplistic helpers for rendering HTML and boilerplate.
 
 Specific to Squeep Framework Applications, this module has strong opinions and makes many assumptions.
 
 
 Specific to Squeep Framework Applications, this module has strong opinions and makes many assumptions.
 
+Expects `/static/theme.css` and `/static/custom.css` to exist.
+
 ## API
 
 - `initContext(ctx)`
 ## API
 
 - `initContext(ctx)`
@@ -41,4 +43,4 @@ Lists of errors and notices to show at top of page, before main content.
 
 ## Tests
 
 
 ## Tests
 
-`LintHtml` class is a simple wrapper around html-validate package which can report issues with generated html strings.
+`LintHtml` class is a simple wrapper around `html-validate` package which can report issues with generated html strings.
index 7f7021ae010f2a58be394f17e23ea4120a4570d7..e8163abbe41733c0e6af0293b49cf22102a98178 100644 (file)
@@ -19,7 +19,7 @@ const initContext = (ctx) => {
 
 /**
  * Some fields may have values outside normal dates, handle them here.
 
 /**
  * Some fields may have values outside normal dates, handle them here.
- * @param {Date} date
+ * @param {Date|Number} date
  * @param {String} otherwise
  */
 const dateOrNot = (date, otherwise) => {
  * @param {String} otherwise
  */
 const dateOrNot = (date, otherwise) => {
@@ -203,7 +203,8 @@ ${htmlFooter(ctx, options)}
  * @returns {String}
  */
 function renderNavLink(nav) {
  * @returns {String}
  */
 function renderNavLink(nav) {
-  return `<a href="${nav.href}"${nav.class ? (' class="' + nav.class + '"') : ''}>${nav.text}</a>`;
+  const aClass = nav.class ? ` class="${nav.class}"` : '';
+  return `<a href="${nav.href}"${aClass}>${nav.text}</a>`;
 }
 
 
 }
 
 
@@ -277,7 +278,10 @@ ${spacer}</footer>` : '';
  * @returns {String}
  */
 function elementAttributes(attributes) {
  * @returns {String}
  */
 function elementAttributes(attributes) {
-  const attr = Object.entries(attributes).map(([name, value]) => `${name}="${value}"`).join(' ');
+  const attr = Object.entries(attributes).map(([name, value]) => {
+    const v = value ? `="${value}"` : '';
+    return `${name}${v}`;
+  }).join(' ');
   return attr ? ' ' + attr : '';
 }
 
   return attr ? ' ' + attr : '';
 }
 
@@ -295,19 +299,33 @@ function LI(item, indent = 0, attributes = {}) {
 }
 
 
 }
 
 
+/**
+ * Wrap an array of items in a list container element.
+ * @param {String} element
+ * @param {Number} indent
+ * @param {Object} attributes
+ * @param {String[]} items
+ * @param {(item, index, array) => {Object}} itemAttributeGenerator
+ * @returns {String}
+ */
+function listContainer(element, indent, attributes, items, itemAttributeGenerator) {
+  const spacer = '\t'.repeat(indent);
+  return `${spacer}<${element}${elementAttributes(attributes)}>
+${items.map((item, index, array) => LI(item, indent + 1, itemAttributeGenerator(item, index, array))).join('\n')}
+${spacer}</${element}>`;
+}
+
+
 /**
  * Wrap a list of items in an unordered list.
  * @param {String[]} items
  * @param {Number} indent
  * @param {Object} attributes
 /**
  * Wrap a list of items in an unordered list.
  * @param {String[]} items
  * @param {Number} indent
  * @param {Object} attributes
- * @param {(item) => Object} itemAttributeGenerator
+ * @param {(item, index, array) => Object} itemAttributeGenerator
  * @returns {String}
  */
 function UL(items, indent = 0, attributes = {}, itemAttributeGenerator = () => {}) {
  * @returns {String}
  */
 function UL(items, indent = 0, attributes = {}, itemAttributeGenerator = () => {}) {
-  const spacer = '\t'.repeat(indent);
-  return `${spacer}<ul${elementAttributes(attributes)}>
-${items.map((item) => LI(item, indent + 1, itemAttributeGenerator(item))).join('\n')}
-${spacer}</ul>`;
+  return listContainer('ul', indent, attributes, items, itemAttributeGenerator);
 }
 
 
 }
 
 
@@ -316,15 +334,12 @@ ${spacer}</ul>`;
  * @param {String[]} items
  * @param {Number} indent
  * @param {Object} attributes
  * @param {String[]} items
  * @param {Number} indent
  * @param {Object} attributes
- * @param {(item) => Object} itemAttributeGenerator
+ * @param {(item, index, array) => Object} itemAttributeGenerator
  * @returns {String}
  */
 
 function OL(items, indent = 0, attributes = {}, itemAttributeGenerator = () => {}) {
  * @returns {String}
  */
 
 function OL(items, indent = 0, attributes = {}, itemAttributeGenerator = () => {}) {
-  const spacer = '\t'.repeat(indent);
-  return `${spacer}<ol${elementAttributes(attributes)}>
-${items.map((item) => LI(item, indent + 1, itemAttributeGenerator(item))).join('\n')}
-${spacer}</ol>`;
+  return listContainer('ol', indent, attributes, items, itemAttributeGenerator);
 }
 
 
 }
 
 
@@ -404,7 +419,9 @@ module.exports = {
   indented,
   renderNavLink,
   LI,
   indented,
   renderNavLink,
   LI,
+  listContainer,
   UL,
   OL,
   htmlPage,
   UL,
   OL,
   htmlPage,
+  elementAttributes,
 };
 };
index 75481adfee0b010330cc89a39656fd7f28e862ef..c62a3c01161be58bbc283c057bf75240312f941f 100644 (file)
@@ -170,6 +170,17 @@ describe('Template Helper', function () {
     });
   }); // renderNavLink
 
     });
   }); // renderNavLink
 
+  describe('elementAttributes', function () {
+    it('covers', function () {
+      const attributes = {
+        class: 'foo bar',
+        disabled: '',
+      };
+      const result = th.elementAttributes(attributes);
+      assert.strictEqual(result, ' class="foo bar" disabled');
+    });
+  }); // elementAttributes
+
   describe('OL', function () {
     it('covers', function () {
       const result = th.OL(['item', 'another item'], 1, { class: 'class' }, (item) => ({ class: `${item}-class` }));
   describe('OL', function () {
     it('covers', function () {
       const result = th.OL(['item', 'another item'], 1, { class: 'class' }, (item) => ({ class: `${item}-class` }));
@@ -273,6 +284,7 @@ describe('Template Helper', function () {
       ];
     });
     it('covers', async function () {
       ];
     });
     it('covers', async function () {
+      this.slow(1000); // First invocation of htmlLint takes some time.
       const result = th.htmlPage(pagePathLevel, ctx, options, main);
       await htmlLint(result);
       assert(result);
       const result = th.htmlPage(pagePathLevel, ctx, options, main);
       await htmlLint(result);
       assert(result);