Skip to content
This repository has been archived by the owner on May 5, 2022. It is now read-only.

Workaround for <table>{{ rows }}</table> case #2

Open
dy opened this issue Oct 25, 2020 · 11 comments
Open

Workaround for <table>{{ rows }}</table> case #2

dy opened this issue Oct 25, 2020 · 11 comments

Comments

@dy
Copy link

dy commented Oct 25, 2020

The <table>{{ rows }}</table> parsing problem can be reasonably worked around. As mentioned in this comment:

That problem can be addressed symptomatically with a couple of heuristics.

  1. If there's text {{ ... }} right before the empty table, almost likely it was intended to be in the table but parser moved it out.
  2. If the insertion {{ ... }} contains <tbody>, <tr>, <th> etc. - most surely it was supposed to reside in the <table>, these elements have no sense on their own.

These two conditions exclude practical chance user meant to place <tr> (or <thead> etc.) right before the empty <table>.

Reverting the parser mistake by these two heuristics wouldn't be wronger guess than the mistake of the parser itself. (placing <tr>/<thead>/<tbody> content before the empty table to the table vs placing text content in the table out).

@dy dy changed the title Workaround for table case Workaround for <table>{{ rows }}</table> case Oct 25, 2020
@LeaVerou
Copy link

That seems a bit like too much magic and can end up getting in the way. It also doesn't cover all use cases, what if <table> is not empty but contains e.g. a <thead> and/or a <tfoot> or even one or more <tbody>s? Now you have to define which tables are sufficiently empty for our purposes, making the heuristic even more complicated.

@dy
Copy link
Author

dy commented Nov 19, 2020

2. rule seems to be certain indicator for these cases, no?
What's the possible scenario of tabular element (caption, colgroup, col, thead, tbody, tfoot, tr, td, th) inserted outside of <table>?
What's the possible scenario of non-tabular element inserted inside of <table>?
I don't see these two intersect.

Alternatives like <!--{{ xxx }}--> are too pricey, considering that the problem of <table> kicking out text nodes is quirky.

@LeaVerou
Copy link

  1. rule seems to be certain indicator for these cases, no?

Sure, but changing where the nodes go based on their value means that (in theory) certain substitutions will occur inside the table and others outside, which would be a nightmare to debug.

@dy
Copy link
Author

dy commented Nov 19, 2020

But isn't that what HTML does already with content inside the table?
That's not the proposed practice, but temporary reversal to the edge-case created by HTML itself.

@LeaVerou
Copy link

Yes, but in DOM, if you get a reference to that node and replace it with another node, the node doesn't move back into the table depending on what you replaced it with. It stays outside.

See also https://en.wikipedia.org/wiki/Principle_of_least_astonishment

@dy
Copy link
Author

dy commented Nov 19, 2020

The case of changing from tabular content to non-tabular and back doesn't seem to be practical, rather theoretical purity, which is according to W3C comes last:

In case of conflict, consider users over authors over implementors over specifiers over theoretical purity

From practical point the same strategy is available: the position is chosen once content is available, and that position is kept for the rest of the template lifetime.

Possible problem is if user needs to manipulate template before the content is available. That can be alleviated by the 1. rule, but yes, it's unclear how to handle some exceptions like:

<table>{{a}}<tbody></tbody>{{b}}</table> → {{a}}{{b}}<table><tbody></tbody></table>
<table>{{a}}{{b}}<tbody></tbody></table> → {{a}}{{b}}<table><tbody></tbody></table>

Although for tables the order of children may not play role.

@LeaVerou
Copy link

Ah yeah, I remember citing the Priority of Constituencies in my youth. 😊 Nice idea in theory, in practice users and authors are not above implementors, because when they are, stuff doesn't get implemented so neither authors nor users can use it.

Avoiding surprising, non-overridable heuristics is not theoretical purity though, it's in the interest of authors. It's the authors that would get confused when their nodes are moved around for no obvious reason. The principle of least surprise is a usability principle, and usable APIs serve primarily their users, i.e. the authors.

Anyhow, we've both expressed our views on this heuristic quite extensively, it's time for some more input from other people, so I'm going to sit back and wait for that.

@dy
Copy link
Author

dy commented Nov 19, 2020

I agree 💯 with the principle, but sorry for repeating myself

That's not the proposed practice, but temporary reversal to the edge-case created by HTML itself.

Polyfilling that case for the most practical scenarios is possible. I was hoping not to abandon elegant syntax only because it'd take time for parser implementation to bump up.

Users are not above implementors, but the W3C is. This situation that implementors drive standard is no-win, considering WICG/webcomponents#624 too - right things just get declined, with no reason.

@ghost
Copy link

ghost commented May 28, 2021

I think Justin Fagnani’s first bullet on the linked issue was really underappreciated. I think it makes sense to use the syntax the parser currently calls “bogus comments” for this purpose, given that they are currently never conforming, and work well with tables.

I don’t know if the regular comment syntax should be allowed to form parts too, but to avoid it, maybe a good approach could be to mark these special “bogus comments” in some way. Maybe a new Comment.prototype.part boolean, or perhaps just an internal flag.

Of course, the “bogus comment” approach doesn’t need the braces, just e.g. <?email> would work, but I think differentiating it could be good to allow for the bogus comment syntax to be used in other ways in the future. I think a good syntax could be <?=email> or <?:email>, just because I think it looks cleaner than <?{{email}}>.

@dy
Copy link
Author

dy commented Jan 10, 2022

Ok, there are valid cases where it's impossible to guess where the field came from:

`<table><tr><td>1</td>{{ a }}</tr></table>`
`<table><tr>{{ a }}<td>1</td></tr></table>`

both give same result:

{{a}}<table><tbody><tr><td>1</td></tr></tbody></table>

@dy
Copy link
Author

dy commented Jan 13, 2022

Worked around in fork, seems that <!--{{field}}--> is the simplest workaround for such case - it has nearly 0 cost.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants