karaxnim / karax

Karax. Single page applications for Nim.
MIT License
1.07k stars 90 forks source link

Compiling in js app changes case of attribute #100

Open hiteshjasani opened 5 years ago

hiteshjasani commented 5 years ago

I'm trying to generate some svg and I'm seeing a small difference if I render it in a javascript app versus rendering it on the server.

proc mkCircle*(radius: int, width: int, fill: string,
               msg: string = "success"): VNode =
  let center = width / 2
  result = buildHtml(tdiv):
    svg(width = $width, height = $width, viewBox = &"0 0 {width} {width}"):
      title: text msg
      circle(fill = "LightGreen", stroke = "gray",
              cx = $center, cy = $center, r = $radius)

Now if I render it on the server, it comes out as expected:

proc render(): string =
  let node = buildHtml(tdiv):
    mkCircle(6, 16, "blue", "test")
  result = $node
<svg width="16" height="16" viewBox="0 0 16 16">                     
  <title>test</title>
  <circle fill="LightGreen" stroke="gray" cx="8.0" cy="8.0" r="6" />       
</svg>

However, if I use it in a javascript app as a VNode, then it comes out with the viewBox attribute changing to be all lowercase.

<svg width="16" height="16" viewbox="0 0 16 16">
  <title>test</title>
  <circle fill="LightGreen" stroke="gray" cx="8" cy="8" r="6"></circle>
</svg>

This small change seems to break the svg in the Safari browser. The result is that the browser gives it a height and width of 0 so you can't see it.

My workaround so far has been to generate the svg as an html string and use a verbatim tag to insert it directly.

kidandcat commented 5 years ago

That could be fixed, although is Safari the one doing it wrong:

https://www.w3.org/TR/html51/syntax.html#writing-html-documents-elements

Tags contain a tag name, giving the element’s name. HTML elements all have names that only use alphanumeric ASCII characters. In the HTML syntax, tag names, even those for foreign elements, may be written with any mix of lower- and uppercase letters that, when converted to all-lowercase, matches the element’s tag name; tag names are case-insensitive.

Also: https://www.w3.org/TR/xhtml1/#h-4.2

Element and attribute names must be in lower case

PD: this problem is all around the net https://stackoverflow.com/questions/10390346/why-is-jquery-auto-lower-casing-attribute-values

hiteshjasani commented 5 years ago

... this problem is all around the net

Agreed, it is a problem all around and the HTML standard is that attributes are case-insensitive. However, it appears that the SVG standard is to use case-sensitive attribute names.

From https://w3c.github.io/svgwg/specs/svg-authoring/

Because SVG is case-sensitive (a legacy of its XML origins), the attribute viewBox must have a capital “B”. It's a common mistake to type viewbox instead, which is easily overlooked and frustrates debugging. SVG uses a mix of attribute-name delimiters, including medial camelCase (“viewBox”), lower-case compound (“viewbox”), and kebab-case (“view-box”), so this is a common error. We're sorry about that.

From https://www.w3.org/TR/SVG11/styling.html

Property declarations via presentation attributes are expressed in XML [XML10], which is case-sensitive. CSS property declarations specified either in CSS style sheets or in a ‘style’ attribute, on the other hand, are generally case-insensitive with some exceptions ([CSS2], section 4.1.3).

It really does appear that the SVG designers used a mixture of styles with defining attributes. It's a mess, but it is what it is.

Araq commented 5 years ago

Well ok, how do we fix it?

hiteshjasani commented 5 years ago

Personally I would like to see the following transformations supported (and consistent between c and js compilers):

svg(wiDTH = "16", HeiGht = "16, `viewBox` = "0 0 16 16", `data-foo` = "2", `data-BaR` = "7")

Turns into

<svg width="16" height="16" viewBox="0 0 16 16" data-foo="9" data-BaR="7">

Essentially all attribute names are made lowercase except when they are within backticks. Within backticks, attribute names are kept as is without any transformation. Any names in kebab case (eg. data-foo) must be enclosed within backticks.

I think this should be applied to all HTML and SVG elements so there wouldn't need to be special case rules for one versus the other.