mirror of
https://github.com/netbox-community/netbox.git
synced 2026-03-11 21:12:11 +01:00
* Fixes #20551: Support quick-add form prefix in automatic slug generation The slug generation logic in `reslug.ts` looks for form fields using hard-coded ID selectors like `#id_slug` and `#id_name`. In quick-add modals, Django applies a `quickadd` prefix to form fields (introduced in #20542), resulting in IDs like `#id_quickadd-slug` and `#id_quickadd-name`. The logic couldn't find these prefixed fields, so automatic slug generation failed silently in quick-add modals. This fix updates the field selectors to try both unprefixed and prefixed patterns using the nullish coalescing operator (`??`), checking for the standard field ID first and falling back to the quickadd-prefixed ID if the standard one isn't found. * Address PR feedback The slug generation logic required updates to support form prefixes like `quickadd`. Python-side changes ensure `SlugField.get_bound_field()` updates the `slug-source` attribute to include the form prefix when present, so JavaScript receives the correct prefixed field ID. `SlugWidget.__init__()` now adds a `slug-field` class to enable selector-based field discovery. On the frontend, `reslug.ts` now uses class selectors (`button.reslug` and `input.slug-field`) instead of ID-based lookups, eliminating the need for fallback logic. The template was updated to use `class="reslug"` instead of `id="reslug"` on the button to avoid ID duplication issues.
88 lines
2.3 KiB
Python
88 lines
2.3 KiB
Python
from django import forms
|
|
|
|
__all__ = (
|
|
'ArrayWidget',
|
|
'ChoicesWidget',
|
|
'ClearableFileInput',
|
|
'MarkdownWidget',
|
|
'NumberWithOptions',
|
|
'SlugWidget',
|
|
)
|
|
|
|
|
|
class ClearableFileInput(forms.ClearableFileInput):
|
|
"""
|
|
Override Django's stock ClearableFileInput with a custom template.
|
|
"""
|
|
template_name = 'widgets/clearable_file_input.html'
|
|
|
|
|
|
class MarkdownWidget(forms.Textarea):
|
|
"""
|
|
Provide a live preview for Markdown-formatted content.
|
|
"""
|
|
template_name = 'widgets/markdown_input.html'
|
|
|
|
def __init__(self, attrs=None):
|
|
# Markdown fields should use monospace font
|
|
default_attrs = {
|
|
"class": "font-monospace",
|
|
}
|
|
if attrs:
|
|
default_attrs.update(attrs)
|
|
|
|
super().__init__(default_attrs)
|
|
|
|
|
|
class NumberWithOptions(forms.NumberInput):
|
|
"""
|
|
Number field with a dropdown pre-populated with common values for convenience.
|
|
"""
|
|
template_name = 'widgets/number_with_options.html'
|
|
|
|
def __init__(self, options, attrs=None):
|
|
self.options = options
|
|
super().__init__(attrs)
|
|
|
|
def get_context(self, name, value, attrs):
|
|
context = super().get_context(name, value, attrs)
|
|
context['widget']['options'] = self.options
|
|
return context
|
|
|
|
|
|
class SlugWidget(forms.TextInput):
|
|
"""
|
|
Subclass TextInput and add a slug regeneration button next to the form field.
|
|
"""
|
|
template_name = 'widgets/sluginput.html'
|
|
|
|
def __init__(self, attrs=None):
|
|
local_attrs = {} if attrs is None else attrs.copy()
|
|
if 'class' in local_attrs:
|
|
local_attrs['class'] = f"{local_attrs['class']} slug-field"
|
|
else:
|
|
local_attrs['class'] = 'slug-field'
|
|
super().__init__(local_attrs)
|
|
|
|
|
|
class ArrayWidget(forms.Textarea):
|
|
"""
|
|
Render each item of an array on a new line within a textarea for easy editing/
|
|
"""
|
|
def format_value(self, value):
|
|
if value is None or not len(value):
|
|
return None
|
|
return '\n'.join(value)
|
|
|
|
|
|
class ChoicesWidget(forms.Textarea):
|
|
"""
|
|
Render each key-value pair of a dictionary on a new line within a textarea for easy editing.
|
|
"""
|
|
def format_value(self, value):
|
|
if not value:
|
|
return None
|
|
if type(value) is list:
|
|
return '\n'.join([f'{k}:{v}' for k, v in value])
|
|
return value
|