Skip to content

Commit

Permalink
Allow special characters in quoted attributes.
Browse files Browse the repository at this point in the history
Characters like “<”, “/”, and “>” are special in html and we use them
as boundary markers to determine where we are as we walk through the
result of a tagged template literal callback.

However, it’s perfectly allowable to use the characters in the markup
itself if they’re quoted. Take the following, resonable example:

```
html`<a href="https://example.com" target="${target}">click me</a>`
```

Previously, because of the “/” characters in the “href” attribute
declaration, the “${target}” binding would get missed. This is now
fixed to allow quoted, special characters.
  • Loading branch information
theengineear committed Mar 16, 2023
1 parent b299c62 commit e6878b9
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 3 deletions.
28 changes: 28 additions & 0 deletions test/test-template-engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,34 @@ it('html: renders multiple templates (as content)', () => {
container.remove();
});

it('html: renders elements with special characters in attributes', () => {
// Note the "/", "<", ">", and "&quot;" characters.
const getTemplate = ({ width, height }) => {
return html`\
<svg
id="svg"
class="<><>&quot;&quot;</></>"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
width="${ifDefined(width)}"
height="${ifDefined(height)}">
<circle id="circle" r="${width / 2}" cx="${width / 2}" cy="${height / 2}"></circle>
</svg>`;
};
const container = document.createElement('div');
document.body.append(container);
const width = 24;
const height = 24;
render(container, getTemplate({ width, height }));
const svgBox = container.querySelector('#svg').getBoundingClientRect();
assert(svgBox.width === width);
assert(svgBox.height === height);
const circleBox = container.querySelector('#circle').getBoundingClientRect();
assert(circleBox.width === width);
assert(circleBox.height === height);
container.remove();
});

it('html: self-closing tags work', () => {
const getTemplate = ({ type }) => {
return html`<input type="${nullish(type)}"/>`;
Expand Down
6 changes: 3 additions & 3 deletions x-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -1062,9 +1062,9 @@ class Template {
static #templates = new WeakMap();
static #templateResults = new WeakMap();
static #updaters = new WeakMap();
static #ATTRIBUTE = /<[a-zA-Z0-9-]+[^/<>]* ([a-z][a-z-]*)="$/;
static #BOOLEAN_ATTRIBUTE = /<[a-zA-Z0-9-]+[^/<>]* \?([a-z][a-z-]*)="$/;
static #PROPERTY = /<[a-zA-Z0-9-]+[^/<>]* \.([a-z][a-zA-Z0-9_]*)="$/;
static #ATTRIBUTE = /<[a-zA-Z0-9-]+(?:[^/<>]|"[^"]*")* ([a-z][a-z-]*)="$/;
static #BOOLEAN_ATTRIBUTE = /<[a-zA-Z0-9-]+(?:[^/<>]|"[^"]*")* \?([a-z][a-z-]*)="$/;
static #PROPERTY = /<[a-zA-Z0-9-]+(?:[^/<>]|"[^"]*")* \.([a-z][a-zA-Z0-9_]*)="$/;

#type = null;
#strings = null;
Expand Down

0 comments on commit e6878b9

Please sign in to comment.