Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ print(test)
<div data-employee="101011"></div>
```

Similarly, use `aria_*` for [Aria](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA), `hx_*` for custom [HTMX](https://htmx.org/), and `up_*` for custom [Unpoly](https://unpoly.com/) attributes

You can also modify the attributes of tags through a dictionary-like interface:

```python
Expand All @@ -160,6 +162,18 @@ print(header)
<div id="header"></div>
```

If attributes don't have values, you can explicitly mark them as having no value:

```python
from dominate.util import novalue

link = a(href="https://url.com", up_instant=novalue(), "Click Here)
print(link)
```
```html
<a href="https://url.com" up-instant>Click Here</a>
```

Complex Structures
------------------

Expand Down
14 changes: 11 additions & 3 deletions dominate/dom_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,11 @@ def _render(self, sb, indent_level, indent_str, pretty, xhtml):
for attribute, value in sorted(self.attributes.items()):
if value in (False, None):
continue
val = unicode(value) if isinstance(value, util.text) and not value.escape else util.escape(unicode(value), True)
sb.append(' %s="%s"' % (attribute, val))
elif isinstance(value, util.novalue):
sb.append(' %s' % (attribute, ))
else:
val = unicode(value) if isinstance(value, util.text) and not value.escape else util.escape(unicode(value), True)
sb.append(' %s="%s"' % (attribute, val))

sb.append(' />' if self.is_single and xhtml else '>')

Expand Down Expand Up @@ -440,12 +443,17 @@ def clean_attribute(attribute):
'phor': 'for',
}.get(attribute, attribute)

# A list of attribute prefixes which mean that underscores should be converted to dashes
# This allows attributes like data_username or hx_post become data-username and hx-post
# hx_ prefix is for HTMX and up_ prefix is for Unpoly
SPECIAL_PREFIX_LIST = ('data_', 'aria_', 'up_', 'hx_')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: move this to dominate.ATTR_PREFIXES and add a function to modify it:

ATTR_PREFIXES = ['data_', 'aria_']

def add_attr_prefix(*args: tuple[str]):
  ATTR_PREFIXES.extend(args)

Then, a user who wants to use htmx or unpoly does dominate.add_attr_prefix('hx_', 'up_').

This provides flexibility without the need to support a 3rd party library by name.

Global settings are often discouraged but, in this case, it makes sense IMO since you aren't always guaranteed to have a top level object to configure. The Python stdlib also has top-level global configs for this in a number of places where they make sense.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maye DASHED_ATTRS is the right name for this.


# Workaround for Python's reserved words
if attribute[0] == '_':
attribute = attribute[1:]

# Workaround for dash
special_prefix = any([attribute.startswith(x) for x in ('data_', 'aria_')])
special_prefix = any([attribute.startswith(x) for x in SPECIAL_PREFIX_LIST])
if attribute in set(['http_equiv']) or special_prefix:
attribute = attribute.replace('_', '-').lower()

Expand Down
8 changes: 8 additions & 0 deletions dominate/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,11 @@ def raw(s):
Inserts a raw string into the DOM. Unsafe. Alias for text(x, escape=False)
'''
return text(s, escape=False)

class novalue:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd recommend changing this to set = () so you can do:

tags.a('foo', up_instant=set)

IMO, there is no need for it to be a class and be instantiated every time.

Alternatively or additionally, the html spec refers to such attributes as boolean attributes. So, IMO, the attribute handling code could just look for is True and, if that's the case, set the attr name without the value.

tags.a('foo', up_instant=True)

Personally, I'd just go with supporting True, document it, and and not add the special sentinel value for simplicity sake.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realize boolean attrs are already supported.

'''
A class to mark tag attributes as having no value.
important for libraries like Unpoly which require attribute values like
<a href="https://url.com" up-instant>Link</a>
'''
pass