forked from ungleich-public/dynamicweb
116 lines
4.9 KiB
Python
116 lines
4.9 KiB
Python
from django import forms
|
|
from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
|
|
from django.core.validators import EMPTY_VALUES
|
|
from django.forms import ChoiceField
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
from cms.forms.utils import get_page_choices, get_site_choices
|
|
from cms.forms.validators import validate_url
|
|
from cms.forms.widgets import PageSelectWidget, PageSmartLinkWidget
|
|
from cms.models.pagemodel import Page
|
|
|
|
|
|
class PageSelectFormField(forms.MultiValueField):
|
|
"""
|
|
Behaves like a :class:`django.forms.ModelChoiceField` field for the
|
|
:class:`cms.models.pagemodel.Page` model, but displays itself as a split
|
|
field with a select drop-down for the site and one for the page. It also
|
|
indents the page names based on what level they're on, so that the page
|
|
select drop-down is easier to use. This takes the same arguments as
|
|
:class:`django.forms.ModelChoiceField`.
|
|
"""
|
|
widget = PageSelectWidget
|
|
default_error_messages = {
|
|
'invalid_site': _('Select a valid site'),
|
|
'invalid_page': _('Select a valid page'),
|
|
}
|
|
|
|
def __init__(self, queryset=None, empty_label="---------", cache_choices=False,
|
|
required=True, widget=None, to_field_name=None, limit_choices_to=None, *args, **kwargs):
|
|
errors = self.default_error_messages.copy()
|
|
if 'error_messages' in kwargs:
|
|
errors.update(kwargs['error_messages'])
|
|
self.limit_choices_to = limit_choices_to
|
|
kwargs['required'] = required
|
|
fields = (
|
|
ChoiceField(choices=get_site_choices, required=False, error_messages={'invalid': errors['invalid_site']}),
|
|
ChoiceField(choices=get_page_choices, required=False, error_messages={'invalid': errors['invalid_page']}),
|
|
)
|
|
|
|
# Remove the unexpected blank kwarg if it's supplied,
|
|
# causes an error where the MultiValueField doesn't expect it
|
|
# https://github.com/django/django/commit/da79ee472d803963dc3ea81ee67767dc06068aac
|
|
if 'blank' in kwargs:
|
|
del kwargs['blank']
|
|
|
|
super().__init__(fields, *args, **kwargs)
|
|
|
|
def compress(self, data_list):
|
|
if data_list:
|
|
page_id = data_list[1]
|
|
|
|
if page_id in EMPTY_VALUES:
|
|
if not self.required:
|
|
return None
|
|
raise forms.ValidationError(self.error_messages['invalid_page'])
|
|
return Page.objects.get(pk=page_id)
|
|
return None
|
|
|
|
def has_changed(self, initial, data):
|
|
is_empty = data and (len(data) >= 2 and data[1] in [None, ''])
|
|
|
|
if isinstance(self.widget, RelatedFieldWidgetWrapper):
|
|
self.widget.decompress = self.widget.widget.decompress
|
|
|
|
if is_empty and initial is None:
|
|
# when empty data will have [u'1', u'', u''] as value
|
|
# this will cause django to always return True because of the '1'
|
|
# so we simply follow django's default behavior when initial is None and data is "empty"
|
|
data = ['' for x in range(0, len(data))]
|
|
return super().has_changed(initial, data)
|
|
|
|
def _has_changed(self, initial, data):
|
|
return self.has_changed(initial, data)
|
|
|
|
|
|
class PageSmartLinkField(forms.CharField):
|
|
"""
|
|
A field making use of ``cms.forms.widgets.PageSmartLinkWidget``.
|
|
This field will offer you a list of matching internal pages as you type.
|
|
You can either pick one or enter an arbitrary URL to create a non-existing entry.
|
|
Takes a `placeholder_text` argument to define the text displayed inside the
|
|
input before you type.
|
|
|
|
The widget uses an ajax request to try to find pages match. It will try to find
|
|
case-insensitive matches amongst public and published pages on the `title`, `path`,
|
|
`page_title`, `menu_title` fields.
|
|
|
|
.. note::
|
|
|
|
``PageSmartLinkField`` stores its value as a plain URL string, so links
|
|
do not follow pages that are later moved or renamed. For dynamically
|
|
linking to pages, other CMS content, or external URLs, the preferred
|
|
approach is the ``LinkField`` provided by
|
|
`djangocms-link <https://github.com/django-cms/djangocms-link>`_, which
|
|
keeps references stable across moves and supports a configurable set of
|
|
link targets.
|
|
"""
|
|
widget = PageSmartLinkWidget
|
|
default_validators = [validate_url]
|
|
|
|
def __init__(self, max_length=None, min_length=None, placeholder_text=None,
|
|
ajax_view=None, *args, **kwargs):
|
|
self.placeholder_text = placeholder_text
|
|
widget = self.widget(ajax_view=ajax_view)
|
|
super().__init__(
|
|
max_length=max_length, min_length=min_length, widget=widget, *args, **kwargs
|
|
)
|
|
|
|
def widget_attrs(self, widget):
|
|
attrs = super().widget_attrs(widget)
|
|
attrs.update({'placeholder_text': self.placeholder_text})
|
|
return attrs
|
|
|
|
def clean(self, value):
|
|
value = self.to_python(value).strip()
|
|
return super().clean(value)
|