mirror of
https://github.com/pretix/pretix.git
synced 2026-06-11 01:25:13 +00:00
move reldate.js include in correct file
This commit is contained in:
@@ -19,10 +19,12 @@
|
|||||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||||
# <https://www.gnu.org/licenses/>.
|
# <https://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
import copy
|
||||||
import datetime
|
import datetime
|
||||||
import os
|
import os
|
||||||
import warnings
|
import warnings
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from dataclasses import dataclass
|
||||||
from typing import (
|
from typing import (
|
||||||
TYPE_CHECKING, Iterable, List, Literal, Tuple, Union,
|
TYPE_CHECKING, Iterable, List, Literal, Tuple, Union,
|
||||||
)
|
)
|
||||||
@@ -41,16 +43,21 @@ from rest_framework import serializers
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .models import Event, Order, SubEvent
|
from .models import Event, Order, SubEvent
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
class BaseChoice:
|
class BaseChoice:
|
||||||
def __init__(self, base: Literal["event", "order"], attribute: str, text: Promise, supports_before: bool,
|
base: Literal["event", "order", "order.subevents"]
|
||||||
supports_after: bool) -> None:
|
attribute: str
|
||||||
self.base = base
|
modifier: str
|
||||||
self.attribute = attribute
|
text: Promise
|
||||||
self.text = text
|
supports_before: bool
|
||||||
self.supports_before = supports_before
|
supports_after: bool
|
||||||
self.supports_after = supports_after
|
|
||||||
self.key = f"{self.base}__{self.attribute}"
|
@property
|
||||||
|
def key(self) -> str:
|
||||||
|
key = f"{self.base}__{self.attribute}"
|
||||||
|
if self.modifier:
|
||||||
|
key += f"__{self.modifier}"
|
||||||
|
return key
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def find(objects: Iterable["BaseChoice"], key: str) -> "BaseChoice":
|
def find(objects: Iterable["BaseChoice"], key: str) -> "BaseChoice":
|
||||||
@@ -67,13 +74,19 @@ class BaseChoice:
|
|||||||
|
|
||||||
|
|
||||||
BASE_CHOICES: List[BaseChoice] = [
|
BASE_CHOICES: List[BaseChoice] = [
|
||||||
BaseChoice('event', 'date_from', _('Event start'), True, True),
|
BaseChoice('event', 'date_from', "", _('Event start'), True, True),
|
||||||
BaseChoice('event', 'date_to', _('Event end'), True, True),
|
BaseChoice('event', 'date_to', "", _('Event end'), True, True),
|
||||||
BaseChoice('event', 'date_admission', _('Event admission'), True, True),
|
BaseChoice('event', 'date_admission', "", _('Event admission'), True, True),
|
||||||
BaseChoice('event', 'presale_start', _('Presale start'), True, True),
|
BaseChoice('event', 'presale_start', "", _('Presale start'), True, True),
|
||||||
BaseChoice('event', 'presale_end', _('Presale end'), True, True),
|
BaseChoice('event', 'presale_end', "", _('Presale end'), True, True),
|
||||||
BaseChoice('order', 'datetime', _('Order creation'), False, True),
|
BaseChoice('order', 'datetime', "", _('Order creation'), False, True),
|
||||||
BaseChoice('order', 'expires', _('Order expiry'), True, True),
|
BaseChoice('order', 'expires', "", _('Order expiry'), True, True),
|
||||||
|
BaseChoice('order.subevents', 'date_from', "first", _('Subevent start (first subevent in order)'), True, True),
|
||||||
|
BaseChoice('order.subevents', 'date_from', "last", _('Subevent start (last subevent in order)'), True, True),
|
||||||
|
BaseChoice('order.subevents', 'date_to', "first", _('Subevent end (first subevent in order)'), True, True),
|
||||||
|
BaseChoice('order.subevents', 'date_to', "last", _('Subevent end (last subevent in order)'), True, True),
|
||||||
|
BaseChoice('order.subevents', 'date_admission', "first", _('Subevent admission (first subevent in order)'), True, True),
|
||||||
|
BaseChoice('order.subevents', 'date_admission', "last", _('Subevent admission (last subevent in order)'), True, True),
|
||||||
]
|
]
|
||||||
|
|
||||||
LIMIT_FALLBACKS = ['date_from', 'date_to', 'date_admission', 'presale_start', 'presale_end']
|
LIMIT_FALLBACKS = ['date_from', 'date_to', 'date_admission', 'presale_start', 'presale_end']
|
||||||
@@ -86,7 +99,11 @@ ORDER_BASE_CHOICES = [
|
|||||||
x for x in BASE_CHOICES if x.base == 'order'
|
x for x in BASE_CHOICES if x.base == 'order'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
SUBEVENT_BASE_CHOICES = [
|
||||||
|
x for x in BASE_CHOICES if x.base == 'order.subevents'
|
||||||
|
]
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
class RelativeDate:
|
class RelativeDate:
|
||||||
"""
|
"""
|
||||||
This contains information on a date that is defined in relation to a fixed base point.
|
This contains information on a date that is defined in relation to a fixed base point.
|
||||||
@@ -97,25 +114,28 @@ class RelativeDate:
|
|||||||
If the base_date_key is not set, the date_from attribute of Event is used.
|
If the base_date_key is not set, the date_from attribute of Event is used.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, days: int = 0, minutes: int = None, time: datetime.time = None, is_after: bool = False,
|
days: int = 0
|
||||||
base_date_name: str = 'event__date_from') -> None:
|
minutes: int = None
|
||||||
choice = BaseChoice.find(BASE_CHOICES, base_date_name)
|
time: datetime.time = None
|
||||||
self.base = choice.base
|
is_after: bool = False
|
||||||
self.attribute = choice.attribute
|
base_date_name: str = 'event__date_from__'
|
||||||
|
|
||||||
if is_after and not choice.supports_after:
|
def __post_init__(self) -> None:
|
||||||
|
if self.is_after and not self._choice.supports_after:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"The selected base date and attribute combination does not support relative dates placed after the base date"
|
"The selected base date and attribute combination does not support relative dates placed after the base date"
|
||||||
)
|
)
|
||||||
if not is_after and not choice.supports_before:
|
if not self.is_after and not self._choice.supports_before:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"The selected base date and attribute combination does not support relative dates placed before the base date")
|
"The selected base date and attribute combination does not support relative dates placed before the base date")
|
||||||
self.is_after = is_after
|
|
||||||
|
|
||||||
self.days = days
|
@property
|
||||||
self.minutes = minutes
|
def _choice(self):
|
||||||
self.time = time
|
return BaseChoice.find(BASE_CHOICES, self.base_date_name)
|
||||||
self.key = choice.key
|
|
||||||
|
@property
|
||||||
|
def key(self):
|
||||||
|
return self._choice.key
|
||||||
|
|
||||||
def __eq__(self, o: object) -> bool:
|
def __eq__(self, o: object) -> bool:
|
||||||
if not isinstance(o, RelativeDate):
|
if not isinstance(o, RelativeDate):
|
||||||
@@ -130,17 +150,35 @@ class RelativeDate:
|
|||||||
"""
|
"""
|
||||||
from .models import Event, Order, SubEvent
|
from .models import Event, Order, SubEvent
|
||||||
|
|
||||||
if self.base == "order" and isinstance(base, Order):
|
choice = self._choice
|
||||||
|
|
||||||
|
if choice.base == "order" and isinstance(base, Order):
|
||||||
event = base.event
|
event = base.event
|
||||||
base_date = getattr(base, self.attribute)
|
base_date = getattr(base, choice.attribute)
|
||||||
elif self.base == "event" and isinstance(base, SubEvent):
|
elif choice.base == "order.subevent" and isinstance(base, Order):
|
||||||
|
if not base.event.has_subevents:
|
||||||
|
raise ValueError("The order is for an event without subevents")
|
||||||
|
if choice.modifier == "first":
|
||||||
|
op = base.all_positions.order_by(f"subevent__{choice.attribute}").first()
|
||||||
|
if op is None:
|
||||||
|
raise ValueError("The order has no positions for subevents")
|
||||||
|
event = op.event
|
||||||
|
base_date = getattr(base, choice.attribute)
|
||||||
|
elif choice.modifier == "last":
|
||||||
|
op = base.all_positions.order_by(f"subevent__{choice.attribute}").last()
|
||||||
|
if op is None:
|
||||||
|
raise ValueError("The order has no positions for subevents")
|
||||||
|
base_date = getattr(base, choice.attribute)
|
||||||
|
else:
|
||||||
|
raise ValueError("The selected modifier does not exist")
|
||||||
|
elif choice.base == "event" and isinstance(base, SubEvent):
|
||||||
event = base.event
|
event = base.event
|
||||||
base_date = (getattr(base, self.attribute) or
|
base_date = (getattr(base, self.attribute) or
|
||||||
getattr(base.event, self.attribute) or
|
getattr(base.event, self.attribute) or
|
||||||
base.date_from)
|
base.date_from)
|
||||||
elif self.base == "event" and isinstance(base, Event):
|
elif choice.base == "event" and isinstance(base, Event):
|
||||||
event = base
|
event = base
|
||||||
base_date = getattr(base, self.attribute) or event.date_from
|
base_date = getattr(base, choice.attribute) or event.date_from
|
||||||
else:
|
else:
|
||||||
raise TypeError("The base defined by data does not match the passed in base")
|
raise TypeError("The base defined by data does not match the passed in base")
|
||||||
|
|
||||||
@@ -189,13 +227,13 @@ class RelativeDate:
|
|||||||
if self.minutes is not None:
|
if self.minutes is not None:
|
||||||
return 'RELDATE/minutes/{}/{}/{}'.format( #
|
return 'RELDATE/minutes/{}/{}/{}'.format( #
|
||||||
self.minutes,
|
self.minutes,
|
||||||
self.key,
|
self._choice.key,
|
||||||
'after' if self.is_after else '',
|
'after' if self.is_after else '',
|
||||||
)
|
)
|
||||||
return 'RELDATE/{}/{}/{}/{}'.format( #
|
return 'RELDATE/{}/{}/{}/{}'.format( #
|
||||||
self.days,
|
self.days,
|
||||||
self.time.strftime('%H:%M:%S') if self.time else '-',
|
self.time.strftime('%H:%M:%S') if self.time else '-',
|
||||||
self.key,
|
self._choice.key,
|
||||||
'after' if self.is_after else '',
|
'after' if self.is_after else '',
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -304,13 +342,20 @@ reldatetimeparts = namedtuple('reldatetimeparts', (
|
|||||||
reldatetimeparts.indizes = reldatetimeparts(*range(9))
|
reldatetimeparts.indizes = reldatetimeparts(*range(9))
|
||||||
|
|
||||||
|
|
||||||
|
def _get_choices(choices: List[BaseChoice])->List[Tuple[str, Promise]]:
|
||||||
|
return [(c.key, c.text) for c in choices]
|
||||||
|
|
||||||
|
def _get_choice_validation_obj(choices: List[BaseChoice]):
|
||||||
|
return {c.key: {"data-supports-before": c.supports_before, "data-supports-after": c.supports_after} for c in choices}
|
||||||
|
|
||||||
|
|
||||||
class RelativeDateTimeWidget(forms.MultiWidget):
|
class RelativeDateTimeWidget(forms.MultiWidget):
|
||||||
template_name = 'pretixbase/forms/widgets/reldatetime.html'
|
template_name = 'pretixbase/forms/widgets/reldatetime.html'
|
||||||
parts = reldatetimeparts
|
parts = reldatetimeparts
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.status_choices = kwargs.pop('status_choices')
|
self.status_choices = kwargs.pop('status_choices')
|
||||||
base_choices = kwargs.pop('base_choices')
|
self.base_choices = kwargs.pop('base_choices')
|
||||||
|
|
||||||
def placeholder_datetime_format():
|
def placeholder_datetime_format():
|
||||||
df = get_format('DATETIME_INPUT_FORMATS')[0]
|
df = get_format('DATETIME_INPUT_FORMATS')[0]
|
||||||
@@ -328,14 +373,14 @@ class RelativeDateTimeWidget(forms.MultiWidget):
|
|||||||
attrs={'placeholder': lazy(placeholder_datetime_format, str), 'class': 'datetimepicker'}
|
attrs={'placeholder': lazy(placeholder_datetime_format, str), 'class': 'datetimepicker'}
|
||||||
),
|
),
|
||||||
rel_days_number=forms.NumberInput(),
|
rel_days_number=forms.NumberInput(),
|
||||||
rel_mins_relationto=forms.Select(choices=base_choices),
|
rel_mins_relationto=OptionAttrsSelect(attrs={'data-relative-choice': True}, choices=self.base_choices, option_attrs=_get_choice_validation_obj(self.base_choices)),
|
||||||
rel_days_timeofday=forms.TimeInput(
|
rel_days_timeofday=forms.TimeInput(
|
||||||
attrs={'placeholder': lazy(placeholder_time_format, str), 'class': 'timepickerfield'}
|
attrs={'placeholder': lazy(placeholder_time_format, str), 'class': 'timepickerfield'}
|
||||||
),
|
),
|
||||||
rel_mins_number=forms.NumberInput(),
|
rel_mins_number=forms.NumberInput(),
|
||||||
rel_days_relationto=forms.Select(choices=base_choices),
|
rel_days_relationto=OptionAttrsSelect(attrs={'data-relative-choice': True}, choices=self.base_choices, option_attrs=_get_choice_validation_obj(self.base_choices)),
|
||||||
rel_mins_relation=forms.Select(choices=BEFORE_AFTER_CHOICE),
|
rel_mins_relation=forms.Select(attrs={'data-relation-choice': True}, choices=BEFORE_AFTER_CHOICE),
|
||||||
rel_days_relation=forms.Select(choices=BEFORE_AFTER_CHOICE),
|
rel_days_relation=forms.Select(attrs={'data-relation-choice': True},choices=BEFORE_AFTER_CHOICE),
|
||||||
)
|
)
|
||||||
super().__init__(widgets=widgets, *args, **kwargs)
|
super().__init__(widgets=widgets, *args, **kwargs)
|
||||||
|
|
||||||
@@ -401,6 +446,8 @@ class RelativeDateTimeWidget(forms.MultiWidget):
|
|||||||
for w in ctx['widget']['subwidgets']
|
for w in ctx['widget']['subwidgets']
|
||||||
))._asdict()
|
))._asdict()
|
||||||
|
|
||||||
|
ctx['choice_validation'] = _get_choice_validation_obj(self.base_choices)
|
||||||
|
ctx['choice_validation_name'] = f'{name}_val'
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
@@ -412,31 +459,34 @@ class RelativeDateTimeField(forms.MultiValueField):
|
|||||||
('relative_minutes', _('Relative time:')),
|
('relative_minutes', _('Relative time:')),
|
||||||
]
|
]
|
||||||
self.relative_to_order = kwargs.pop('relative_to_order', False)
|
self.relative_to_order = kwargs.pop('relative_to_order', False)
|
||||||
|
self.relative_to_subevent_positions = kwargs.pop('relative_to_subevent_positions', False)
|
||||||
|
|
||||||
all_choices = EVENT_BASE_CHOICES
|
possible_choices = copy.deepcopy(EVENT_BASE_CHOICES)
|
||||||
if self.relative_to_order:
|
if self.relative_to_order:
|
||||||
all_choices.extend(ORDER_BASE_CHOICES)
|
possible_choices.extend(ORDER_BASE_CHOICES)
|
||||||
|
if self.relative_to_subevent_positions:
|
||||||
|
possible_choices.extend(SUBEVENT_BASE_CHOICES)
|
||||||
|
|
||||||
if kwargs.get('limit_choices'):
|
if kwargs.get('limit_choices'):
|
||||||
limit = kwargs.pop('limit_choices')
|
limit = kwargs.pop('limit_choices')
|
||||||
if any("__" not in l for l in limit):
|
if any(["__" not in l for l in limit]):
|
||||||
_warn_skips = (os.path.dirname(__file__),)
|
_warn_skips = (os.path.dirname(__file__),)
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
"Please prefix limit_choices with the base the attributes refer to, for example event__date_from",
|
"Please prefix limit_choices with the base the attributes refer to, for example event__date_from",
|
||||||
skip_file_prefixes=_warn_skips)
|
skip_file_prefixes=_warn_skips)
|
||||||
|
|
||||||
choices = [(c.key, c.text) for c in all_choices if
|
possible_choices = [c for c in possible_choices if
|
||||||
# new base case as we want limit_choices to be expressed as base__attribute
|
# new base case as we want limit_choices to be expressed as base__attribute
|
||||||
(c.key in limit) or
|
(c.key in limit) or
|
||||||
# fallback for old event based entries
|
# fallback for old event based entries
|
||||||
# if the base is an event, then using only attribute is fine
|
# if the base is an event, then using only attribute is fine
|
||||||
(c.base == "event" and c.attribute in limit)]
|
(c.base == "event" and c.attribute in limit)]
|
||||||
else:
|
|
||||||
choices = [(c.key, c.text) for c in all_choices]
|
|
||||||
|
|
||||||
if not kwargs.get('required', True):
|
if not kwargs.get('required', True):
|
||||||
status_choices.insert(0, ('unset', _('Not set')))
|
status_choices.insert(0, ('unset', _('Not set')))
|
||||||
|
|
||||||
|
choices = _get_choices(possible_choices)
|
||||||
|
|
||||||
fields = reldatetimeparts(
|
fields = reldatetimeparts(
|
||||||
status=forms.ChoiceField(
|
status=forms.ChoiceField(
|
||||||
choices=status_choices,
|
choices=status_choices,
|
||||||
@@ -471,8 +521,9 @@ class RelativeDateTimeField(forms.MultiValueField):
|
|||||||
required=False
|
required=False
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
if 'widget' not in kwargs:
|
if 'widget' not in kwargs:
|
||||||
kwargs['widget'] = RelativeDateTimeWidget(status_choices=status_choices, base_choices=choices)
|
kwargs['widget'] = RelativeDateTimeWidget(status_choices=status_choices, base_choices=possible_choices)
|
||||||
kwargs.pop('max_length', 0)
|
kwargs.pop('max_length', 0)
|
||||||
kwargs.pop('empty_value', 0)
|
kwargs.pop('empty_value', 0)
|
||||||
super().__init__(
|
super().__init__(
|
||||||
@@ -480,11 +531,15 @@ class RelativeDateTimeField(forms.MultiValueField):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def set_event(self, event):
|
def set_event(self, event):
|
||||||
choices = [
|
possible_choices = copy.deepcopy(EVENT_BASE_CHOICES)
|
||||||
(c.key, c.text) for c in EVENT_BASE_CHOICES if getattr(event, c.attribute, None)
|
|
||||||
]
|
|
||||||
if self.relative_to_order:
|
if self.relative_to_order:
|
||||||
choices += [(c.key, c.text) for c in ORDER_BASE_CHOICES]
|
possible_choices.extend(ORDER_BASE_CHOICES)
|
||||||
|
if self.relative_to_subevent_positions and event.has_subevents:
|
||||||
|
possible_choices.extend(SUBEVENT_BASE_CHOICES)
|
||||||
|
|
||||||
|
possible_choices = possible_choices
|
||||||
|
choices = _get_choices(possible_choices)
|
||||||
|
|
||||||
self.widget.widgets[reldatetimeparts.indizes.rel_days_relationto].choices = choices
|
self.widget.widgets[reldatetimeparts.indizes.rel_days_relationto].choices = choices
|
||||||
self.widget.widgets[reldatetimeparts.indizes.rel_mins_relationto].choices = choices
|
self.widget.widgets[reldatetimeparts.indizes.rel_mins_relationto].choices = choices
|
||||||
|
|
||||||
@@ -529,15 +584,15 @@ class RelativeDateTimeField(forms.MultiValueField):
|
|||||||
elif data.status == 'relative':
|
elif data.status == 'relative':
|
||||||
choice = BaseChoice.find(BASE_CHOICES, data.rel_days_relationto)
|
choice = BaseChoice.find(BASE_CHOICES, data.rel_days_relationto)
|
||||||
if data.rel_days_relation == "before" and not choice.supports_before:
|
if data.rel_days_relation == "before" and not choice.supports_before:
|
||||||
raise ValidationError(_("A relative date cannot be expressed as 'before' for '{}'".format(choice.text)))
|
raise ValidationError(_('A relative date cannot be expressed as "before" for "{}"'.format(choice.text)))
|
||||||
elif data.status == 'relative' and data.rel_days_relation == "after" and not choice.supports_after:
|
elif data.status == 'relative' and data.rel_days_relation == "after" and not choice.supports_after:
|
||||||
raise ValidationError(_("A relative date cannot be expressed as 'after' for '{}'".format(choice.text)))
|
raise ValidationError(_('A relative date cannot be expressed as "after" for "{}"'.format(choice.text)))
|
||||||
elif data.status == 'relative_minutes':
|
elif data.status == 'relative_minutes':
|
||||||
choice = BaseChoice.find(BASE_CHOICES, data.rel_days_relationto)
|
choice = BaseChoice.find(BASE_CHOICES, data.rel_days_relationto)
|
||||||
if data.rel_days_relation == "before" and not choice.supports_before:
|
if data.rel_days_relation == "before" and not choice.supports_before:
|
||||||
raise ValidationError(_("A relative time cannot be expressed as 'before' for '{}'".format(choice.text)))
|
raise ValidationError(_('A relative time cannot be expressed as "before" for "{}"'.format(choice.text)))
|
||||||
elif data.rel_days_relation == "after" and not choice.supports_after:
|
elif data.rel_days_relation == "after" and not choice.supports_after:
|
||||||
raise ValidationError(_("A relative time cannot be expressed as 'after' for '{}'".format(choice.text)))
|
raise ValidationError(_('A relative time cannot be expressed as "after" for "{}"'.format(choice.text)))
|
||||||
|
|
||||||
return super().clean(value)
|
return super().clean(value)
|
||||||
|
|
||||||
@@ -558,15 +613,20 @@ class RelativeDateWidget(RelativeDateTimeWidget):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.status_choices = kwargs.pop('status_choices')
|
self.status_choices = kwargs.pop('status_choices')
|
||||||
base_choices = kwargs.pop('base_choices')
|
self.base_choices = kwargs.pop('base_choices')
|
||||||
|
|
||||||
widgets = reldateparts(
|
widgets = reldateparts(
|
||||||
status=forms.RadioSelect(choices=self.status_choices),
|
status=forms.RadioSelect(choices=self.status_choices),
|
||||||
absolute=forms.DateInput(
|
absolute=forms.DateInput(
|
||||||
attrs={'class': 'datepickerfield'}
|
attrs={'class': 'datepickerfield'}
|
||||||
),
|
),
|
||||||
rel_days_number=forms.NumberInput(),
|
rel_days_number=forms.NumberInput(),
|
||||||
rel_days_relationto=forms.Select(choices=base_choices),
|
rel_days_relationto=OptionAttrsSelect(
|
||||||
rel_days_relation=forms.Select(choices=BEFORE_AFTER_CHOICE),
|
choices=self.base_choices,
|
||||||
|
option_attrs=_get_choice_validation_obj(self.base_choices),
|
||||||
|
attrs={'data-relative-choice': True},
|
||||||
|
),
|
||||||
|
rel_days_relation=forms.Select(choices=BEFORE_AFTER_CHOICE, attrs={'data-relation-choice': True},),
|
||||||
)
|
)
|
||||||
forms.MultiWidget.__init__(self, widgets=widgets, *args, **kwargs)
|
forms.MultiWidget.__init__(self, widgets=widgets, *args, **kwargs)
|
||||||
|
|
||||||
@@ -599,6 +659,13 @@ class RelativeDateWidget(RelativeDateTimeWidget):
|
|||||||
rel_days_relation="after" if value.data.is_after else "before"
|
rel_days_relation="after" if value.data.is_after else "before"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_context(self, name, value, attrs):
|
||||||
|
ctx = super().get_context(name, value, attrs)
|
||||||
|
|
||||||
|
ctx['choice_validation'] = _get_choice_validation_obj(self.base_choices)
|
||||||
|
ctx['choice_validation_name'] = f'{name}_val'
|
||||||
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
class RelativeDateField(RelativeDateTimeField):
|
class RelativeDateField(RelativeDateTimeField):
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@
|
|||||||
<script type="text/javascript" src="{% static "leaflet/leaflet.js" %}"></script>
|
<script type="text/javascript" src="{% static "leaflet/leaflet.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "pretixcontrol/js/ui/geo.js" %}"></script>
|
<script type="text/javascript" src="{% static "pretixcontrol/js/ui/geo.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "pretixbase/js/details.js" %}"></script>
|
<script type="text/javascript" src="{% static "pretixbase/js/details.js" %}"></script>
|
||||||
|
<script type="text/javascript" src="{% static "pretixbase/js/reldate.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "pretixbase/js/asynctask.js" %}"></script>
|
<script type="text/javascript" src="{% static "pretixbase/js/asynctask.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "sortable/Sortable.js" %}"></script>
|
<script type="text/javascript" src="{% static "sortable/Sortable.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "colorpicker/bootstrap-colorpicker.js" %}"></script>
|
<script type="text/javascript" src="{% static "colorpicker/bootstrap-colorpicker.js" %}"></script>
|
||||||
|
|||||||
@@ -22,5 +22,4 @@
|
|||||||
<script type="text/javascript" src="{% static "pretixpresale/js/ui/iframe.js" %}"></script>
|
<script type="text/javascript" src="{% static "pretixpresale/js/ui/iframe.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "pretixbase/js/addressform.js" %}"></script>
|
<script type="text/javascript" src="{% static "pretixbase/js/addressform.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "pretixbase/js/deanonymize_email.js" %}"></script>
|
<script type="text/javascript" src="{% static "pretixbase/js/deanonymize_email.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static 'pretixbase/js/reldate.js' %}" ></script>
|
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
|
|||||||
Reference in New Issue
Block a user