Documentation
¶
Overview ¶
Command bindings turns framework attribute syntax into plain HTML attributes where it can, and says why it cannot everywhere else.
$ bindings page.html
9 bindings: 4 rewritten, 5 left alone
rewritten
:title="'Home'" -> title="Home"
v-bind:id="'main'" -> id="main"
[attr.role]="'nav'" -> role="nav"
:hidden="true" -> hidden="true"
left alone
:href="url" the value is an expression, and nothing here evaluates one
@click="go" an event handler has no plain form
*ngIf="ok" a structural directive decides whether the element exists
[(ngModel)]="v" two-way binding has no plain form
v-html="body" writing markup from a binding is not a plain attribute
Only a literal can become a plain attribute: a quoted string, a number, true or false. An expression needs a runtime, and a program that guessed would produce a page that looks right and says something else.
A template is not HTML, and its compiler is case-sensitive ¶
The tokenizer lower-cases attribute names, because HTML matches them case-insensitively. A framework template is HTML-shaped text read by something that does not:
source Attribute.Name Attribute.NamePreserveCase *ngIf="ok" *ngif *ngIf [ngClass]="c" [ngclass] [ngClass] [(ngModel)]="v" [(ngmodel)] [(ngModel)] v-bind:someProp v-bind:someprop v-bind:someProp @myEvent @myevent @myEvent
`*ngIf` is a directive and `*ngif` is not, so a report built from Name names something the author cannot find, and an attribute *added* as `*ngIf` arrives as `*ngif` and stops working - lolhtml.Element.SetAttribute lower-cases a name it is adding and keeps the document's spelling for one already there. This program reads NamePreserveCase for everything it prints and never adds a name with a capital in it: the plain attributes it writes are lower-case by definition, which is the only reason it is safe to write them at all.
The same rule is documented for SVG, where viewbox is not viewBox. A template compiler is the second consumer of the same kind, and there will be others: the question is not whether the document is HTML but whether whoever reads it next cares about case.
Why the selectors are not used ¶
Every one of these names needs escaping to appear in a selector, because the characters that make them recognisable are the characters CSS uses for something else:
[\:href] [\@click] [\*ngIf] [\(click\)] [\[ngClass\]] [\[\(ngModel\)\]]
Those all work, and are tested. What this program does instead is match every element and read its attribute list, because a page can carry a dozen prefixes and one selector per prefix is a dozen registrations to keep in step with a list that is only going to grow. The escaping is worth knowing about anyway: an unescaped `[:href]` is a rejected selector rather than one that matches nothing, so it fails loudly - see the package documentation on escaping.