Skip to content

Commit

Permalink
Implement closing an element by another element's opening tag based o…
Browse files Browse the repository at this point in the history
…n pre-defined pairings

I wanted to avoid this, but I don't think `HTMLRewriter` exposes enough information for me to be able to do it.
  • Loading branch information
TomasHubelbauer committed Oct 13, 2024
1 parent cc094ed commit e2ad8c8
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 6 deletions.
7 changes: 7 additions & 0 deletions index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,11 @@ test('NEXTID', async () => {
expect(document.body.outerHTML).toEqual(`<body><header><title></title><nextid /></header></body>`);
});

// See http://info.cern.ch/hypertext/WWW/TheProject.html
test('DL & DT & DD', async () => {
const domParser = new DOMParser();
const document = await domParser.parseFromString(`<DL><DT><A></A><DD><A></A><A></A><DT><A></A><DD><A></A></DL>`);
expect(document.body.outerHTML).toEqual(`<body><dl><dt><a></a></dt><dd><a></a><a></a></dd><dt><a></a></dt><dd><a></a></dd></dl></body>`);
});

// TODO: Use full http://info.cern.ch/hypertext/WWW/TheProject.html as one of the tests
21 changes: 15 additions & 6 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ class Text implements Node {
parentElement: Element;
}

// TODO: See if we can use some API from `HTMLRewriter` to not have to keep this
// Note that the `HTMLRewriter` tag names are always lowercase despite source HTML
const autoClosingTags: { [tag: string]: string[] } = {
'DD': ['DT'],
'DT': ['DD'],
'P': ['DD', 'P'],
'DL': ['P'],
'dd': ['dt'],
'dt': ['dd'],
'p': ['dd', 'p'],
'dl': ['p'],
};

/**
Expand Down Expand Up @@ -143,14 +143,23 @@ export default class DOMParser {
document.activeElement = document.body;
}

// Handle an unclosed element being followed by an opening tag for another element
if (autoClosingTags[element.tagName]?.includes(document.activeElement.tagName)) {
document.activeElement = document.activeElement.parentElement;
}

const activeElement = document.createElement(element.tagName);
document.activeElement.append(activeElement);
document.activeElement = activeElement;

element.onEndTag((tag) => {
// Handle an unclosed element being followed by a closing tag for another element
// Keep closing the element chain as void elements until we find the matching tag
while (document.activeElement?.parentElement && tag.name !== document.activeElement.tagName) {
document.activeElement.isVoid = true;
// Mark as void only if there are no children, otherwise it is a
// case of an element with no closing tag closed by another
// element's opening tag via `autoClosingTags`
document.activeElement.isVoid = document.activeElement.children.length === 0;
document.activeElement = document.activeElement.parentElement;
}

Expand Down

0 comments on commit e2ad8c8

Please sign in to comment.