Skip to content

Commit

Permalink
Fix JavaScript and HTML errors
Browse files Browse the repository at this point in the history
There were 176 JavaScript and legacy HTML errors. This commit fixes that.

This commit:

- Fixes eslint errors, ignoring only the resolution of the csv-parse library. From quick research, this is a common problem.
- Fixes HTML validation errors, making tags compliant. (e.g. wraps <figcaption> in <figure>)
- Sets the passthrough mode in 11ty. Adding `assets/` as a passthrough caused "not a directory" errors, and setting this mode fixed those errors.
- Changes some .md files to .html. Several files were HTML but rendering as Markdown, resulting in the Markdown renderer adding tons of extraneous <p> or </p> tags but not closing them.
- Incidentally reorganizes services_projects folder to projects/services/.

HTML is not guaranteed to be fully correct.
  • Loading branch information
beechnut committed Jun 4, 2024
1 parent 884acc1 commit 02d74e4
Show file tree
Hide file tree
Showing 47 changed files with 328 additions and 384 deletions.
143 changes: 63 additions & 80 deletions .eleventy.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
const fs = require('fs');
const { EleventyRenderPlugin } = require("@11ty/eleventy");
const { EleventyRenderPlugin } = require('@11ty/eleventy');
const pluginRss = require('@11ty/eleventy-plugin-rss');
const pluginNavigation = require('@11ty/eleventy-navigation');
const markdownIt = require('markdown-it');
const markdownItAttrs = require('markdown-it-attrs');
const markdownItAnchor = require('markdown-it-anchor');
const markdownItFootnote = require('markdown-it-footnote');
const svgSprite = require('eleventy-plugin-svg-sprite');
const syntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight');
const yaml = require('js-yaml');
const { parse } = require('csv-parse/sync'); /* eslint-disable-line import/no-unresolved */
const { readableDate
, htmlDateString
, head
, min
, filterTagList
, embed
, team_photo
, team_link
, find_collection
, teamPhoto
, teamLink
, findCollection
, markdownify
, weighted_sort
, in_groups
, weightedSort
, inGroups
, oembed
, relative_url
, match_posts } = require("./config/filters");
const { headingLinks } = require("./config/headingLinks");
const { contrastRatio, humanReadableContrastRatio } = require("./config/wcagColorContrast");
const privateLinks = require ('./config/privateLinksList.js');
const svgSprite = require("eleventy-plugin-svg-sprite");
const syntaxHighlight = require("@11ty/eleventy-plugin-syntaxhighlight");
const yaml = require("js-yaml");
const { parse } = require('csv-parse/sync');
, asRelativeUrl
, matchPosts } = require('./config/filters');
const { headingLinks } = require('./config/headingLinks');
const { contrastRatio, humanReadableContrastRatio } = require('./config/wcagColorContrast');
const privateLinks = require ('./config/privateLinksList');

const { imageShortcode, imageWithClassShortcode } = require('./config');

Expand All @@ -39,15 +39,18 @@ module.exports = function (config) {

config.addPlugin(EleventyRenderPlugin);

// copying assets did something weird and this fixed it
config.setServerPassthroughCopyBehavior('passthrough');
// Copy the `admin` folders to the output
config.addPassthroughCopy('admin');
config.addPassthroughCopy('assets');

// Copy USWDS init JS so we can load it in HEAD to prevent banner flashing
config.addPassthroughCopy({'./node_modules/@uswds/uswds/dist/js/uswds-init.js': 'assets/js/uswds-init.js'});

// Specific scripts to guides
config.addPassthroughCopy("./assets/_common/js/*");
config.addPassthroughCopy("./assets/**/js/*");
config.addPassthroughCopy('./assets/_common/js/*');
config.addPassthroughCopy('./assets/**/js/*');

// @TODO This is one place where the _site/img folder gets produced
// Let's find a way to keep everything in assets
Expand All @@ -61,16 +64,16 @@ module.exports = function (config) {
config.addPlugin(pluginRss);
config.addPlugin(pluginNavigation);

//// SVG Sprite Plugin for USWDS USWDS icons
/// / SVG Sprite Plugin for USWDS USWDS icons
config.addPlugin(svgSprite, {
path: "./node_modules/@uswds/uswds/dist/img/uswds-icons",
path: './node_modules/@uswds/uswds/dist/img/uswds-icons',
svgSpriteShortcode: 'uswds_icons_sprite',
svgShortcode: 'uswds_icons'
});

//// SVG Sprite Plugin for USWDS USA icons
/// / SVG Sprite Plugin for USWDS USA icons
config.addPlugin(svgSprite, {
path: "./node_modules/@uswds/uswds/dist/img/usa-icons",
path: './node_modules/@uswds/uswds/dist/img/usa-icons',
svgSpriteShortcode: 'usa_icons_sprite',
svgShortcode: 'usa_icons'
});
Expand All @@ -79,11 +82,9 @@ module.exports = function (config) {
config.addPlugin(syntaxHighlight);

// Allow yaml to be used in the _data dir
config.addDataExtension("yml, yaml", contents => yaml.load(contents));
config.addDataExtension('yml, yaml', contents => yaml.load(contents));

config.addDataExtension("csv", (contents) => {
return parse(contents, {columns: true, skip_empty_lines: true});
});
config.addDataExtension('csv', (contents) => parse(contents, {columns: true, skip_empty_lines: true}));


// Filters
Expand All @@ -98,25 +99,17 @@ module.exports = function (config) {
// Add an iframe / embedded content
config.addFilter('embed', embed);
// Add a photo for an 18F team member
config.addFilter('team_photo', team_photo);
config.addFilter('team_photo', teamPhoto);
// Add a link to an 18F team member's author page
config.addFilter('team_link', team_link);
config.addFilter('find_collection', find_collection);
config.addFilter('weighted_sort', weighted_sort);
config.addFilter('in_groups', in_groups);
config.addFilter('team_link', teamLink);
config.addFilter('find_collection', findCollection);
config.addFilter('weighted_sort', weightedSort);
config.addFilter('in_groups', inGroups);
config.addShortcode('oembed', oembed);
config.addFilter('relative_url', relative_url);
config.addFilter('match_posts', match_posts);
config.addFilter("limit", function (arr, limit) {
return arr.slice(0, limit);
});
config.addFilter('matching', function(collection, author) {
return collection.filter((post) => {
return post.data.authors.includes(author)
});
});

// FIXME (see other FIXME)
config.addFilter('relative_url', asRelativeUrl);
config.addFilter('match_posts', matchPosts);
config.addFilter('limit', (arr, limit) => arr.slice(0, limit));
config.addFilter('matching', (collection, author) => collection.filter((post) => post.data.authors.includes(author)));
config.addFilter('markdownify', markdownify);

// Color contrast checkers for the color matrix in the Brand guide
Expand All @@ -125,54 +118,46 @@ module.exports = function (config) {

// Create absolute urls
config.addFilter('asAbsoluteUrl', (relativeUrl) => {
const host = siteData.host;
const {host} = siteData;
return new URL(relativeUrl, host).href;
});

config.addFilter("makeUppercase", (value) => {
return value.toUpperCase();
});
config.addFilter('makeUppercase', (value) => value.toUpperCase());

config.addFilter("capitalize", (value) =>{
return value.charAt(0).toUpperCase() + value.slice(1);
});
config.addFilter('capitalize', (value) =>value.charAt(0).toUpperCase() + value.slice(1));

// Converts strings or dates to date objects
const dateObject = ((date) => {
switch(typeof date) {
case "object": return date;
case "string": return new Date(date)
case 'object': return date;
case 'string': return new Date(date);
default: throw new Error(`Expected date (${date}) to be string or object`)
}
})

// Generates the "yyyy/mm/dd" part of permalinks for blog posts
// @example date is Jan 1, 2020
// returns "2020/01/01"
config.addFilter("toDatePath", (date) => {
return dateObject(date).toISOString().split('T')[0].split('-').join('/')
});
config.addFilter('toDatePath', (date) => dateObject(date).toISOString().split('T')[0].split('-').join('/'));

// TODO: Not sure this is returning exactly the right string, re: datetimes
config.addFilter("date_to_xmlschema", (date) => {
return dateObject(date).toISOString()
});
config.addFilter('date_to_xmlschema', (date) => dateObject(date).toISOString());

// Create an array of all tags
config.addCollection('tagList', function (collection) {
let tagSet = new Set();
config.addCollection('tagList', (collection) => {
const tagSet = new Set();
collection.getAll().forEach((item) => {
(item.data.tags || []).forEach((tag) => tagSet.add(tag));
});

return filterTagList([...tagSet]);
});

config.addCollection('post', function (collection) {
return collection.getFilteredByGlob('content/posts/*.md')
});
config.addCollection('post', (collection) => collection.getFilteredByGlob('content/posts/*.md'));
config.addCollection('service', (collection) => collection.getFilteredByGlob('content/pages/projects/services/*.md'));

// Customize Markdown library and settings
let markdownLibrary = markdownIt({
const markdownLibrary = markdownIt({
html: true,
breaks: false,
linkify: false,
Expand Down Expand Up @@ -213,7 +198,7 @@ module.exports = function (config) {
const baseURL = new URL('https://guides.18f.gov/');
const hrefValue = token.attrGet('href');

if (!(new URL(hrefValue, baseURL).hostname.endsWith(".gov"))) {
if (!(new URL(hrefValue, baseURL).hostname.endsWith('.gov'))) {
// Add the external link class if it hasn't been added yet
if (!(token.attrGet('class')) || !(token.attrGet('class').includes('usa-link--external'))) {
token.attrJoin('class', 'usa-link usa-link--external');
Expand All @@ -224,7 +209,7 @@ module.exports = function (config) {
token.attrJoin('rel', 'noreferrer');
}
}
return openDefaultRender(tokens, idx, options, env, self) + `${prefixIcon}`;
return `${openDefaultRender(tokens, idx, options, env, self) }${prefixIcon}`;
};

const defaultHtmlBlockRender = markdownLibrary.renderer.rules.html_block ||
Expand All @@ -234,10 +219,10 @@ module.exports = function (config) {

markdownLibrary.renderer.rules.html_block = (tokens, idx, options, env, self) => {
const token = tokens[idx];
let content = token.content;
let {content} = token;
// Capture the class portion of the element if it exists so it can be interacted with later
// https://regexr.com/7udrd
const hrefRE = /<a href=\"[^"]*\" class=\"([^"]*)\">|href=\"([^"]*)\"/g;
const hrefRE = /<a href="[^"]*" class="([^"]*)">|href="([^"]*)"/g;
const htmlIncludesLinks = content.includes('http') && hrefRE.test(token.content);

if (htmlIncludesLinks) {
Expand All @@ -248,15 +233,15 @@ module.exports = function (config) {
if (!anchorElement.includes('class=')) {
if (!anchorElement.includes('usa-link--external')) {
// Since no class is present, we can safely just append our classes after the href property
const newUrl = anchorElement + ' class="usa-link usa-link--external"';
const newUrl = `${anchorElement } class="usa-link usa-link--external"`;
content = content.replace(anchorElement, newUrl);
tokens[idx].content = content;
}
} else {
// Handle URLs with classes already present
const classRE = /class="([^"]*)"/;
const [classString, oldClassList] = anchorElement.match(classRE);
const newClassList = oldClassList + ' usa-link usa-link--external';
const newClassList = `${oldClassList } usa-link usa-link--external`;

// If someone uses the class property but doesn't actually put any classes in it, the class list will be empty
if (classString === 'class=""') {
Expand All @@ -283,10 +268,10 @@ module.exports = function (config) {
markdownLibrary.renderer.rules.html_inline = (tokens, idx, options, env, self) => {
const token=tokens[idx];
if (linkOpenRE.test(token.content) && token.content.includes('http')) {
let content = token.content;
let {content} = token;

//Add private link icon
const hrefRE = /href=\"([^"]*)/;
// Add private link icon
const hrefRE = /href="([^"]*)/;
// get the matching capture group
const contentUrl = content.match(hrefRE)[1];
if (privateLinks.some((privateLink) => contentUrl.indexOf(privateLink) >= 0)) {
Expand Down Expand Up @@ -329,13 +314,13 @@ module.exports = function (config) {
// Override Browsersync defaults (used only with --serve)
config.setBrowserSyncConfig({
callbacks: {
ready: function (err, browserSync) {
const content_404 = fs.readFileSync('_site/404/index.html');
ready (err, browserSync) {
const content404 = fs.readFileSync('_site/404/index.html');

browserSync.addMiddleware('*', (req, res) => {
// Provides the 404 content without redirect.
res.writeHead(404, { 'Content-Type': 'text/html; charset=UTF-8' });
res.write(content_404);
res.write(content404);
res.end();
});
},
Expand All @@ -347,12 +332,10 @@ module.exports = function (config) {
// Set image shortcodes
config.addLiquidShortcode('image', imageShortcode);
config.addLiquidShortcode('image_with_class', imageWithClassShortcode);
config.addLiquidShortcode("uswds_icon", function (name) {
return `
config.addLiquidShortcode('uswds_icon', (name) => `
<svg class="usa-icon" aria-hidden="true" role="img">
<use xlink:href="#svg-${name}"></use>
</svg>`;
});
</svg>`);

// If BASEURL env variable exists, update pathPrefix to the BASEURL
if (process.env.BASEURL) {
Expand Down Expand Up @@ -385,7 +368,7 @@ module.exports = function (config) {
// You can also pass this in on the command line using `--pathprefix`

// Optional (default is shown)
pathPrefix: pathPrefix,
pathPrefix,
// -----------------------------------------------------------------

// These are all optional (defaults are shown):
Expand Down
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"es2021": true,
"mocha": true
},
"ignorePatterns": ["/_site"],
"ignorePatterns": ["_site/", "assets/", "!.eleventy.js"],
"extends": ["eslint-config-airbnb-base", "prettier"],
"parserOptions": {
"ecmaVersion": "latest",
Expand Down
5 changes: 0 additions & 5 deletions _data/assetPaths.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
{
"admi.js": "/assets/_common/js/admin.js",
"ap.js": "/assets/_common/js/app.js",
"inde.html": "/assets/presentations/presentation-README/index.html",
"admin.js": "/assets/js/admin-3AAZDPS4.js",
"admin.map": "/assets/js/admin-3AAZDPS4.js.map",
"app.js": "/assets/js/app-VJ5WPKYD.js",
"app.map": "/assets/js/app-VJ5WPKYD.js.map",
"external.js": "/assets/js/external-links.js",
"uswds.js": "/assets/js/uswds-init.js",
"styles.css": "/assets/styles/styles-YNYM6ERT.css",
"styles.map": "/assets/styles/styles-YNYM6ERT.css.map"
}
32 changes: 16 additions & 16 deletions _includes/card-with-image-guides.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{% comment %}
This partial outputs a card with a heading, icon, descriptive text, a link, and, optionally, a hero image.
It was spun off from the "card-with-image" partial to accomodate the unique needs of the guides index page.
The whole card is no longer a clickable link. In the future, these might be condensed back down
into a single partial and class, but it will probably require some more conditional statements
because the behaviors are so different.
This partial outputs a card with a heading, icon, descriptive text, a link, and, optionally, a hero image.
It was spun off from the "card-with-image" partial to accomodate the unique needs of the guides index page.
The whole card is no longer a clickable link. In the future, these might be condensed back down
into a single partial and class, but it will probably require some more conditional statements
because the behaviors are so different.

The expected arguments for this partial are:
link_url - the url the links on the card will link to (href)
Expand All @@ -23,27 +23,27 @@

<!--The card only attempts to render a hero image (and the background color) if it has one assigned, which right now is only reserved for guides labeled "important"-->
<!--Using a few inline styles here to force the hero div to respect the border radii of the card, but there might be a more elegant way of doing that-->
{% if include.hero_url %}
{% if hero_url %}
<div class="padding-4 display-flex flex-column bg-primary-dark" style="border-top-left-radius:inherit; border-top-right-radius: inherit;">
<img class="flex-align-self-center maxh-card-lg" alt="" src="{{ site.baseurl }}{{include.hero_url}}">
<img class="flex-align-self-center maxh-card-lg" alt="" src="{{ site.baseurl }}{{ hero_url }}">
</div>
{% endif %}

<div class="padding-4 display-flex flex-column flex-align-stretch card-content">
<div class="margin-bottom-2 display-flex flex-align-center {%- if include.image_side == "right" %} flex-justify {% endif %} height-full">
<div class="margin-bottom-2 display-flex flex-align-center {%- if image_side == "right" %} flex-justify {% endif %} height-full">

{% capture card_image %}
<img src="{{ site.baseurl }}{{include.image_path}}"
class="{%- if include.image_size == "md" -%}maxw-8 height-8 {%- else -%} maxw-6 height-6 {%- endif %} margin-top-0 {%- unless include.image_side == "right" %} margin-right-2 {% endunless %}"
alt="{{- include.image_alt_text -}}"
<img src="{{ site.baseurl }}{{image_path}}"
class="{%- if image_size == "md" -%}maxw-8 height-8 {%- else -%} maxw-6 height-6 {%- endif %} margin-top-0 {%- unless image_side == "right" %} margin-right-2 {% endunless %}"
alt="{{- image_alt_text -}}"
>
{% endcapture %}

{% capture card_text %}
<h3 class="text-bold margin-y-0">{{ include.text_content }}</h3>
<h3 class="text-bold margin-y-0">{{ text_content }}</h3>
{% endcapture %}

{% if include.image_side == "right" %}
{% if image_side == "right" %}
{{ card_text }}
{{ card_image }}
{% else %}
Expand All @@ -52,8 +52,8 @@ <h3 class="text-bold margin-y-0">{{ include.text_content }}</h3>
{% endif %}

</div>
<p class="font-sans-md margin-y-0 text-no-underline">{{ include.text_descrip }}</p>
<a href="{{include.link_url}}" class="text-bold flex-align-end">Read <span class="text-lowercase">{{ include.text_content }}</span> guide</a>

<p class="font-sans-md margin-y-0 text-no-underline">{{ text_descrip }}</p>
<a href="{{ link_url }}" class="text-bold flex-align-end">Read <span class="text-lowercase">{{ text_content }}</span> guide</a>
</div>
</div>
Loading

0 comments on commit 02d74e4

Please sign in to comment.