Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Boolean HTML attribute behavior under >3.8.0 #381

Closed
mcdonc opened this issue Aug 25, 2023 · 2 comments
Closed

Boolean HTML attribute behavior under >3.8.0 #381

mcdonc opened this issue Aug 25, 2023 · 2 comments

Comments

@mcdonc
Copy link
Contributor

mcdonc commented Aug 25, 2023

I have been tasked with trying to figure out why templates rendered using Chameleon < 3.8.0 render differently semantically than templates rendered under 3.8.0 and greater.

I was pointed at Pylons/pyramid_chameleon#31 which sorta.. kinda? describes the problem, but not fully. The diagnosis reached within that issue was for pyramid_chameleon to use a boolean_attributes argument to PageTemplate but I am afraid to report that this doesn't actually solve the problem.

The issue is with (braindead) HTML attributes which can valueless like "checked", "selected", etc, and whose mere presence indicates that they are true (their value is ignored).

Below I'm going to repeat the findings I came up with in Pylons/pyramid_chameleon#31 (comment) which explain the problem in depth. TLDR: when boolean_attributes is used, rendering one of those braindead attributes works properly when it is replaced using tal:attributes but not when it is replaced using squiggly brace syntax. If someone can point me at the code that I might should change in Chameleon to fix this, I would be grateful, because this behavior change causes fifteen years of templates to need to be reviewed and changed, which is too much work to ponder.

Anyway....

Here's a program that renders several templates. Some should be detected as
HTML by Chameleon, some as XML, and their output should probably differ based
on whether Chameleon believes they are HTML or XML (spoiler alert: they don't).
Each uses the tal:attribute spelling and the inline curly brace spelling to
replace a checked attribute.

from chameleon import PageTemplate

boolean_attributes= [
        # From http://www.w3.org/TR/xhtml1/#guidelines (C.10)
        "compact",
        "nowrap",
        "ismap",
        "declare",
        "noshade",
        "checked",
        "disabled",
        "readonly",
        "multiple",
        "selected",
        "noresize",
        "defer",
    ]

booleans_html5 = """<!DOCTYPE html>
<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" tal:attributes="checked checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="${checked}"/>
  </form>
</body>
</html>
"""

booleans_htmlfrag = """<form>
  <!-- tal:attributes="checked checked"-->
  <input type="checkbox" tal:attributes="checked checked"/>
  <!-- checked="$\{checked}"-->
  <input type="checkbox" selected="${checked}"/>
</form>
"""

booleans_nodoctype = """<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" tal:attributes="checked checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="${checked}"/>
  </form>
</body>
</html>
"""

booleans_xhtml = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" tal="">
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" tal:attributes="checked checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="${checked}"/>
  </form>
</body>
</html>
"""

booleans_xml = """<?xml version="1.0" ?>
<!-- tal:attributes="checked checked"-->
<input type="checkbox" tal:attributes="checked checked" />
<!-- checked="$\{checked}"-->
<input type="checkbox" checked="${checked}" />
"""

for name in (
    "booleans_html5",
    "booleans_htmlfrag",
    "booleans_nodoctype",
    "booleans_xhtml",
    "booleans_xml",
    ):
    inputstr = locals()[name]
    template = PageTemplate(inputstr, boolean_attributes=boolean_attributes)
    print('------------------------------------------------')
    print(name)
    print('------------------------------------------------')
    print(inputstr)
    print()
    print('---checked=True----')
    print(template(checked=True))
    print('---checked=False---')
    print(template(checked=False))
    print()

Here's the output of that program using Chameleon 3.7.4:

------------------------------------------------
booleans_html5
------------------------------------------------
<!DOCTYPE html>
<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" tal:attributes="checked checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="${checked}"/>
  </form>
</body>
</html>


---checked=True----
<!DOCTYPE html>
<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" checked="checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="True"/>
  </form>
</body>
</html>

---checked=False---
<!DOCTYPE html>
<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox"/>

</form>
</body>
</html>


------------------------------------------------
booleans_htmlfrag
------------------------------------------------
<form>
  <!-- tal:attributes="checked checked"-->
  <input type="checkbox" tal:attributes="checked checked"/>
  <!-- checked="$\{checked}"-->
  <input type="checkbox" selected="${checked}"/>
</form>


---checked=True----
<form>
  <!-- tal:attributes="checked checked"-->
  <input type="checkbox" checked="checked"/>
  <!-- checked="$\{checked}"-->
  <input type="checkbox" selected="True"/>
</form>

---checked=False---
<form>
  <!-- tal:attributes="checked checked"-->
  <input type="checkbox"/>
  <!-- checked="$\{checked}"-->
  <input type="checkbox"/>
</form>


------------------------------------------------
booleans_nodoctype
------------------------------------------------
<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" tal:attributes="checked checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="${checked}"/>
  </form>
</body>
</html>


---checked=True----
<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" checked="checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="True"/>
  </form>
</body>
</html>

---checked=False---
<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox"/>
  </form>
</body>
</html>


------------------------------------------------
booleans_xhtml
------------------------------------------------
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" tal="">
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" tal:attributes="checked checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="${checked}"/>
  </form>
</body>
</html>


---checked=True----
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" tal="">
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" checked="checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="True"/>
  </form>
</body>
</html>

---checked=False---
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" tal="">
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox"/>
  </form>
</body>
</html>


------------------------------------------------
booleans_xml
------------------------------------------------
<?xml version="1.0" ?>
<!-- tal:attributes="checked checked"-->
<input type="checkbox" tal:attributes="checked checked" />
<!-- checked="$\{checked}"-->
<input type="checkbox" checked="${checked}" />


---checked=True----
<?xml version="1.0" ?>
<!-- tal:attributes="checked checked"-->
<input type="checkbox" checked="checked" />
<!-- checked="$\{checked}"-->
<input type="checkbox" checked="True" />

---checked=False---
<?xml version="1.0" ?>
<!-- tal:attributes="checked checked"-->
<input type="checkbox" />
<!-- checked="$\{checked}"-->
<input type="checkbox" />

Here's the output of the same program under Chameleon 3.8.0:

------------------------------------------------
booleans_html5
------------------------------------------------
<!DOCTYPE html>
<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" tal:attributes="checked checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="${checked}"/>
  </form>
</body>
</html>


---checked=True----
<!DOCTYPE html>
<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" checked="checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="True"/>
  </form>
</body>
</html>

---checked=False---
<!DOCTYPE html>
<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="False"/>
  </form>
</body>
</html>


------------------------------------------------
booleans_htmlfrag
------------------------------------------------
<form>
  <!-- tal:attributes="checked checked"-->
  <input type="checkbox" tal:attributes="checked checked"/>
  <!-- checked="$\{checked}"-->
  <input type="checkbox" selected="${checked}"/>
</form>


---checked=True----
<form>
  <!-- tal:attributes="checked checked"-->
  <input type="checkbox" checked="checked"/>
  <!-- checked="$\{checked}"-->
  <input type="checkbox" selected="True"/>
</form>

---checked=False---
<form>
  <!-- tal:attributes="checked checked"-->
  <input type="checkbox"/>
  <!-- checked="$\{checked}"-->
  <input type="checkbox" selected="False"/>
</form>


------------------------------------------------
booleans_nodoctype
------------------------------------------------
<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" tal:attributes="checked checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="${checked}"/>
  </form>
</body>
</html>


---checked=True----
<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" checked="checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="True"/>
  </form>
</body>
</html>

---checked=False---
<html>
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="False"/>
  </form>
</body>
</html>


------------------------------------------------
booleans_xhtml
------------------------------------------------
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" tal="">
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" tal:attributes="checked checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="${checked}"/>
  </form>
</body>
</html>


---checked=True----
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" tal="">
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox" checked="checked"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="True"/>
  </form>
</body>
</html>

---checked=False---
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" tal="">
<head>
  <title>Title of document</title>
</head>
<body>
  <form>
    <!-- tal:attributes="checked checked"-->
    <input type="checkbox"/>
    <!-- checked="$\{checked}"-->
    <input type="checkbox" checked="False"/>
  </form>
</body>
</html>


------------------------------------------------
booleans_xml
------------------------------------------------
<?xml version="1.0" ?>
<!-- tal:attributes="checked checked"-->
<input type="checkbox" tal:attributes="checked checked" />
<!-- checked="$\{checked}"-->
<input type="checkbox" checked="${checked}" />


---checked=True----
<?xml version="1.0" ?>
<!-- tal:attributes="checked checked"-->
<input type="checkbox" checked="checked" />
<!-- checked="$\{checked}"-->
<input type="checkbox" checked="True" />

---checked=False---
<?xml version="1.0" ?>
<!-- tal:attributes="checked checked"-->
<input type="checkbox" />
<!-- checked="$\{checked}"-->
<input type="checkbox" checked="False" />

Note that under 3.7.4 when "checked" is False, the checked attribute is
left off the element, even under the XML case (where it presumably should not
be), no matter whether we use tal:attributes or a curly brace statement to
represent "checked".

Under 3.8 (and master), the "checked" attribute is only left off when we use tal:attributes.

@malthe
Copy link
Owner

malthe commented Aug 26, 2023

I have started a branch here, currently with a failing test:

https://github.com/malthe/chameleon/tree/issue-381-boolean-attributes

The failed tests show that the following fails to take boolean_attributes into account:

  • Dynamic attributes (i.e., using a dictionary to set attributes dynamically)
  • Using $-syntax for interpolation

In both cases, we just get the rendered boolean value instead of the attribute name.

@mcdonc
Copy link
Contributor Author

mcdonc commented Aug 29, 2023

Thanks for the work!

I added a comment at #382 (comment) about the empty-string case.

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

No branches or pull requests

2 participants