Compare commits

..
Author SHA1 Message Date
Richard Schreiber 5aa8b6c329 Close dialog onclick on backdrop 2025-05-21 20:47:17 +02:00
luelistaandGitHub a84beef269 [A11y] Cart renewal (#5109)
Allow customers to extend their cart reservation up to 11 times the configured reservation time
2025-05-21 17:02:21 +02:00
Richard SchreiberandGitHub 7c59ec51ca [A11y] switch modal dialogs to <dialog> tag (#5128)
* add templatetag {% dialog %} using <dialog> tag
* new dialog style
* show dialog when empty add-to-cart instead of disabling the button
* update cookieconsent-modal to use new template tag
2025-05-21 16:52:49 +02:00
Richard SchreiberandGitHub bf47da521c [A11y] add heading-level to product list (#5121) 2025-05-21 13:31:05 +02:00
Richard SchreiberandGitHub e3b74249c9 [A11y] fix skip-link z-index (#5123) 2025-05-21 13:30:39 +02:00
Richard SchreiberandGitHub 1791a63f87 [A11y] Do not underline event-titles in organizer’s event-list (#5124) 2025-05-21 13:26:27 +02:00
Raphael Michel f931362bc5 Add missing flag for Basque language 2025-05-21 12:57:19 +02:00
Raphael Michel a836dc1588 Add Hebrew language 2025-05-21 12:52:53 +02:00
Raphael MichelandRaphael Michel 8b6685dd89 Translations: Update Hebrew
Currently translated at 100.0% (5885 of 5885 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/he/

powered by weblate
2025-05-21 12:47:42 +02:00
roi belotsercovskyandRaphael Michel 7463e41be8 Translations: Update Hebrew
Currently translated at 0.0% (0 of 5869 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/he/

powered by weblate
2025-05-21 12:47:42 +02:00
Raphael MichelandRaphael Michel 31b2a9026d Translations: Add Hebrew 2025-05-21 12:47:42 +02:00
Raphael MichelandRaphael Michel 1d49d7cbf7 Translations: Delete Hebrew 2025-05-21 12:47:42 +02:00
조정화andRaphael Michel 30570fe287 Translations: Update Korean
Currently translated at 39.5% (2322 of 5869 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ko/

powered by weblate
2025-05-21 12:47:42 +02:00
roi belotsercovskyandRaphael Michel 00508dea99 Translations: Update Hebrew
Currently translated at 0.1% (1 of 5869 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/he/

powered by weblate
2025-05-21 12:47:42 +02:00
Patrick ChiltonandRaphael Michel 6be4e2bd7b Translations: Update Hungarian
Currently translated at 10.9% (642 of 5869 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/hu/

powered by weblate
2025-05-21 12:47:42 +02:00
bstramsekandRaphael Michel b014446399 Translations: Update Slovenian
Currently translated at 39.3% (96 of 244 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/sl/

powered by weblate
2025-05-21 12:47:42 +02:00
DavidandRaphael Michel 5053d4db6b Translations: Update Czech
Currently translated at 96.3% (235 of 244 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/cs/

powered by weblate
2025-05-21 12:47:42 +02:00
DavidandRaphael Michel ae2cc7a04a Translations: Update Czech
Currently translated at 73.6% (4322 of 5869 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/cs/

powered by weblate
2025-05-21 12:47:42 +02:00
Tobias KunzeandGitHub d49141c05d Use he as language code for Hebrew (#5129) 2025-05-21 12:42:51 +02:00
Richard SchreiberandGitHub 0bbb136d67 [A11y] Fix checkbox:focus style (#5131) 2025-05-21 12:00:34 +02:00
30 changed files with 10044 additions and 12425 deletions
+2 -1
View File
@@ -101,6 +101,7 @@ ALL_LANGUAGES = [
('fi', _('Finnish')),
('gl', _('Galician')),
('el', _('Greek')),
('he', _('Hebrew')),
('id', _('Indonesian')),
('it', _('Italian')),
('ja', _('Japanese')),
@@ -122,7 +123,7 @@ LANGUAGES_OFFICIAL = {
}
LANGUAGES_RTL = {
# When adding more right-to-left languages, also update pretix/static/pretixbase/scss/_rtl.scss
'ar', 'hw'
'ar', 'he'
}
LANGUAGES_INCUBATING = {
'pt-br', 'gl',
@@ -0,0 +1,18 @@
# Generated by Django 4.2.20 on 2025-05-14 14:58
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0279_discount_event_date_from_discount_event_date_until'),
]
operations = [
migrations.AddField(
model_name='cartposition',
name='max_extend',
field=models.DateTimeField(null=True),
),
]
+4 -1
View File
@@ -3098,7 +3098,10 @@ class CartPosition(AbstractPosition):
verbose_name=_("Expiration date"),
db_index=True
)
max_extend = models.DateTimeField(
verbose_name=_("Limit for extending expiration date"),
null=True
)
tax_rate = models.DecimalField(
max_digits=7, decimal_places=2, default=Decimal('0.00'),
verbose_name=_('Tax rate')
+64 -17
View File
@@ -45,6 +45,7 @@ from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import DatabaseError, transaction
from django.db.models import Count, Exists, IntegerField, OuterRef, Q, Value
from django.db.models.aggregates import Min
from django.dispatch import receiver
from django.utils.timezone import make_aware, now
from django.utils.translation import (
@@ -275,7 +276,10 @@ class CartManager:
}
def __init__(self, event: Event, cart_id: str, sales_channel: SalesChannel,
invoice_address: InvoiceAddress=None, widget_data=None, expiry=None):
invoice_address: InvoiceAddress=None, widget_data=None, reservation_time: timedelta=None):
"""
Creates a new CartManager for an event.
"""
self.event = event
self.cart_id = cart_id
self.real_now_dt = now()
@@ -286,11 +290,17 @@ class CartManager:
self._subevents_cache = {}
self._variations_cache = {}
self._seated_cache = {}
self._expiry = None
self._explicit_expiry = expiry
self.invoice_address = invoice_address
self._widget_data = widget_data or {}
self._sales_channel = sales_channel
self.num_extended_positions = 0
if reservation_time:
self._reservation_time = reservation_time
else:
self._reservation_time = timedelta(minutes=self.event.settings.get('reservation_time', as_type=int))
self._expiry = self.real_now_dt + self._reservation_time
self._max_expiry_extend = self.real_now_dt + (self._reservation_time * 11)
@property
def positions(self):
@@ -305,14 +315,6 @@ class CartManager:
self._seated_cache[item, subevent] = item.seat_category_mappings.filter(subevent=subevent).exists()
return self._seated_cache[item, subevent]
def _calculate_expiry(self):
if self._explicit_expiry:
self._expiry = self._explicit_expiry
else:
self._expiry = self.real_now_dt + timedelta(
minutes=self.event.settings.get('reservation_time', as_type=int)
)
def _check_presale_dates(self):
if self.event.presale_start and time_machine_now(self.real_now_dt) < self.event.presale_start:
raise CartError(error_messages['not_started'])
@@ -329,9 +331,27 @@ class CartManager:
raise CartError(error_messages['payment_ended'])
def _extend_expiry_of_valid_existing_positions(self):
# real_now_dt is initialized at CartManager instantiation, so it's slightly in the past. Add a small
# delta to reduce risk of extending already expired CartPositions.
padded_now_dt = self.real_now_dt + timedelta(seconds=5)
# Make sure we do not extend past the max_extend timestamp, allowing users to extend their valid positions up
# to 11 times the reservation time. If we add new positions to the cart while valid positions exist, the new
# positions' reservation will also be limited to max_extend of the oldest position.
# Only after all positions expire, an ExtendOperation may reset max_extend to another 11x reservation_time.
max_extend_existing = self.positions.filter(expires__gt=padded_now_dt).aggregate(m=Min('max_extend'))['m']
if max_extend_existing:
self._expiry = min(self._expiry, max_extend_existing)
self._max_expiry_extend = max_extend_existing
# Extend this user's cart session to ensure all items in the cart expire at the same time
# We can extend the reservation of items which are not yet expired without risk
self.positions.filter(expires__gt=self.real_now_dt).update(expires=self._expiry)
if self._expiry > padded_now_dt:
self.num_extended_positions += self.positions.filter(
expires__gt=padded_now_dt, expires__lt=self._expiry,
).update(
expires=self._expiry,
)
def _delete_out_of_timeframe(self):
err = None
@@ -1246,6 +1266,7 @@ class CartManager:
item=op.item,
variation=op.variation,
expires=self._expiry,
max_extend=self._max_expiry_extend,
cart_id=self.cart_id,
voucher=op.voucher,
addon_to=op.addon_to if op.addon_to else None,
@@ -1294,7 +1315,9 @@ class CartManager:
event=self.event,
item=b.item,
variation=b.variation,
expires=self._expiry, cart_id=self.cart_id,
expires=self._expiry,
max_extend=self._max_expiry_extend,
cart_id=self.cart_id,
voucher=None,
addon_to=cp,
subevent=b.subevent,
@@ -1321,12 +1344,14 @@ class CartManager:
op.position.delete()
elif available_count == 1:
op.position.expires = self._expiry
op.position.max_extend = self._max_expiry_extend
op.position.listed_price = op.listed_price
op.position.price_after_voucher = op.price_after_voucher
# op.position.price will be updated by recompute_final_prices_and_taxes()
if op.position.pk not in deleted_positions:
try:
op.position.save(force_update=True, update_fields=['expires', 'listed_price', 'price_after_voucher'])
op.position.save(force_update=True, update_fields=['expires', 'max_extend', 'listed_price', 'price_after_voucher'])
self.num_extended_positions += 1
except DatabaseError:
# Best effort... The position might have been deleted in the meantime!
pass
@@ -1416,14 +1441,11 @@ class CartManager:
def commit(self):
self._check_presale_dates()
self._check_max_cart_size()
self._calculate_expiry()
err = self._delete_out_of_timeframe()
err = self.extend_expired_positions() or err
err = err or self._check_min_per_voucher()
self.real_now_dt = now()
self._extend_expiry_of_valid_existing_positions()
err = self._perform_operations() or err
self.recompute_final_prices_and_taxes()
@@ -1632,6 +1654,31 @@ def clear_cart(self, event: Event, cart_id: str=None, locale='en', sales_channel
raise CartError(error_messages['busy'])
@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
def extend_cart_reservation(self, event: Event, cart_id: str=None, locale='en', sales_channel='web', override_now_dt: datetime=None) -> None:
"""
Resets the expiry time of a cart to the configured reservation time of this event.
Limited to 11x the reservation time.
:param event: The event ID in question
:param cart_id: The cart ID of the cart to modify
"""
with language(locale), time_machine_now_assigned(override_now_dt):
try:
sales_channel = event.organizer.sales_channels.get(identifier=sales_channel)
except SalesChannel.DoesNotExist:
raise CartError("Invalid sales channel.")
try:
try:
cm = CartManager(event=event, cart_id=cart_id, sales_channel=sales_channel)
cm.commit()
return cm.num_extended_positions
except LockTimeoutException:
self.retry()
except (MaxRetriesExceededError, LockTimeoutException):
raise CartError(error_messages['busy'])
@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
def set_cart_addons(self, event: Event, addons: List[dict], add_to_cart_items: List[dict], cart_id: str=None, locale='en',
invoice_address: int=None, sales_channel='web', override_now_dt: datetime=None) -> None:
+60
View File
@@ -0,0 +1,60 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# 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/>.
#
from django import template
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _ # NOQA
register = template.Library()
@register.simple_tag
def dialog(html_id, label, description, *args, **kwargs):
format_kwargs = {
"id": html_id,
"label": label,
"description": description,
"icon": format_html('<div class="modal-card-icon"><span class="fa fa-{}" aria-hidden="true"></span></div>', kwargs["icon"]) if "icon" in kwargs else "",
"alert": mark_safe('role="alertdialog"') if kwargs.get("alert", "False") != "False" else "",
}
result = """
<dialog {alert}
id="{id}"
aria-labelledby="{id}-label"
aria-describedby="{id}-description">
<form method="dialog" class="modal-card form-horizontal">
{icon}
<div class="modal-card-content">
<h2 id="{id}-label">{label}</h2>
<p id="{id}-description">{description}</p>
"""
return format_html(result, **format_kwargs)
@register.simple_tag
def enddialog(*args, **kwargs):
return mark_safe("""
</div>
</form>
</dialog>
""")
+11 -20
View File
@@ -8,16 +8,16 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-28 11:06+0000\n"
"PO-Revision-Date: 2025-02-19 17:00+0000\n"
"Last-Translator: Petr Čermák <pcermak@live.com>\n"
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix/cs/"
">\n"
"PO-Revision-Date: 2025-05-16 17:00+0000\n"
"Last-Translator: David <davemachala@gmail.com>\n"
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix/cs/>"
"\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Generator: Weblate 5.10\n"
"X-Generator: Weblate 5.11.4\n"
#: pretix/_base_settings.py:87
msgid "English"
@@ -57,7 +57,7 @@ msgstr "Čeština"
#: pretix/_base_settings.py:96
msgid "Croatian"
msgstr ""
msgstr "Chorvatština"
#: pretix/_base_settings.py:97
msgid "Danish"
@@ -2971,12 +2971,9 @@ msgid "Repeat password"
msgstr "Opakovat heslo"
#: pretix/base/forms/questions.py:134 pretix/base/forms/questions.py:256
#, fuzzy
#| msgctxt "subevent"
#| msgid "No date was specified."
msgctxt "name_salutation"
msgid "not specified"
msgstr "Nebylo uvedeno žádné datum."
msgstr "neuvedeno"
#: pretix/base/forms/questions.py:219
msgid "Please do not use special characters in names."
@@ -4227,20 +4224,14 @@ msgstr ""
"automatická sleva poskytnuta i nadále."
#: pretix/base/models/discount.py:177
#, fuzzy
#| msgctxt "subevent"
#| msgid "All dates starting before"
msgctxt "subevent"
msgid "Available for dates starting from"
msgstr "Všechny termíny začínající před"
msgstr "Dostupné pro termíny začínající od"
#: pretix/base/models/discount.py:182
#, fuzzy
#| msgctxt "subevent"
#| msgid "All dates starting before"
msgctxt "subevent"
msgid "Available for dates starting until"
msgstr "Všechny termíny začínající před"
msgstr "Dostupné pro termíny začínající do"
#: pretix/base/models/discount.py:214
msgid ""
@@ -13474,7 +13465,7 @@ msgstr "Schváleno, čeká se na platbu"
#: pretix/plugins/reports/exporters.py:380
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html:7
msgid "Approval pending"
msgstr "Čeká se na schválení"
msgstr "Čeká na schválení"
#: pretix/control/forms/filter.py:241
#, fuzzy
@@ -18849,7 +18840,7 @@ msgstr "Kontrola"
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html:50
#: pretix/control/templates/pretixcontrol/organizers/logs.html:80
msgid "No results"
msgstr "Bez výsledků"
msgstr "Žádné výsledky"
#: pretix/control/templates/pretixcontrol/event/mail.html:7
#: pretix/control/templates/pretixcontrol/organizers/mail.html:11
+35 -58
View File
@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-28 11:08+0000\n"
"PO-Revision-Date: 2025-02-19 17:00+0000\n"
"Last-Translator: Petr Čermák <pcermak@live.com>\n"
"PO-Revision-Date: 2025-05-16 17:00+0000\n"
"Last-Translator: David <davemachala@gmail.com>\n"
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix-js/"
"cs/>\n"
"Language: cs\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Generator: Weblate 5.10\n"
"X-Generator: Weblate 5.11.4\n"
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
@@ -237,11 +237,11 @@ msgstr "Zrušeno"
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:46
msgid "Confirmed"
msgstr ""
msgstr "Potvrzeno"
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:47
msgid "Approval pending"
msgstr ""
msgstr "Čeká na schválení"
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:48
msgid "Redeemed"
@@ -440,7 +440,7 @@ msgstr "je po"
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:40
msgid "="
msgstr ""
msgstr "="
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:99
msgid "Product"
@@ -452,7 +452,7 @@ msgstr "Varianta produktu"
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:107
msgid "Gate"
msgstr ""
msgstr "Brána"
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:111
msgid "Current date and time"
@@ -557,12 +557,12 @@ msgstr "Duplikát"
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:193
msgctxt "entry_status"
msgid "present"
msgstr ""
msgstr "přítomen"
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:194
msgctxt "entry_status"
msgid "absent"
msgstr ""
msgstr "nepřítomen"
#: pretix/static/pretixcontrol/js/ui/editor.js:171
msgid "Check-in QR"
@@ -692,10 +692,8 @@ msgid "Calculating default price…"
msgstr "Výpočet standardní ceny…"
#: pretix/static/pretixcontrol/js/ui/plugins.js:69
#, fuzzy
#| msgid "Search results"
msgid "No results"
msgstr "Vyhledat výsledky"
msgstr "Žádné výsledky"
#: pretix/static/pretixcontrol/js/ui/question.js:42
msgid "Others"
@@ -764,64 +762,57 @@ msgid "Your local time:"
msgstr "Místní čas:"
#: pretix/static/pretixpresale/js/walletdetection.js:39
#, fuzzy
#| msgid "Apple Pay"
msgid "Google Pay"
msgstr "Apple Pay"
msgstr "Google Pay"
#: pretix/static/pretixpresale/js/widget/widget.js:16
msgctxt "widget"
msgid "Quantity"
msgstr ""
msgstr "Počet"
#: pretix/static/pretixpresale/js/widget/widget.js:17
msgctxt "widget"
msgid "Decrease quantity"
msgstr ""
msgstr "Snížit počet"
#: pretix/static/pretixpresale/js/widget/widget.js:18
msgctxt "widget"
msgid "Increase quantity"
msgstr ""
msgstr "Zvýšit počet"
#: pretix/static/pretixpresale/js/widget/widget.js:19
msgctxt "widget"
msgid "Price"
msgstr ""
msgstr "Cena"
#: pretix/static/pretixpresale/js/widget/widget.js:20
#, javascript-format
msgctxt "widget"
msgid "Original price: %s"
msgstr ""
msgstr "Původní cena: %s"
#: pretix/static/pretixpresale/js/widget/widget.js:21
#, javascript-format
msgctxt "widget"
msgid "New price: %s"
msgstr ""
msgstr "Nová cena: %s"
#: pretix/static/pretixpresale/js/widget/widget.js:22
#, fuzzy
#| msgid "Selected only"
msgctxt "widget"
msgid "Select"
msgstr "Pouze vybra"
msgstr "Vybrat"
#: pretix/static/pretixpresale/js/widget/widget.js:23
#, fuzzy, javascript-format
#| msgid "Selected only"
#, javascript-format
msgctxt "widget"
msgid "Select %s"
msgstr "Pouze vybrané"
msgstr "Vybrat %s"
#: pretix/static/pretixpresale/js/widget/widget.js:24
#, fuzzy, javascript-format
#| msgctxt "widget"
#| msgid "See variations"
#, javascript-format
msgctxt "widget"
msgid "Select variant %s"
msgstr "Zobrazit možnosti"
msgstr "Vybrat variantu %s"
#: pretix/static/pretixpresale/js/widget/widget.js:25
msgctxt "widget"
@@ -857,7 +848,7 @@ msgstr "od %(currency)s %(price)s"
#, javascript-format
msgctxt "widget"
msgid "Image of %s"
msgstr ""
msgstr "Obrázek%s"
#: pretix/static/pretixpresale/js/widget/widget.js:32
msgctxt "widget"
@@ -892,24 +883,19 @@ msgstr "K dispozici pouze s poukazem"
#: pretix/static/pretixpresale/js/widget/widget.js:38
#: pretix/static/pretixpresale/js/widget/widget.js:41
#, fuzzy
#| msgid "Payment method unavailable"
msgctxt "widget"
msgid "Not yet available"
msgstr "Způsob platby není k dispozici"
msgstr "Zatím není k dispozici"
#: pretix/static/pretixpresale/js/widget/widget.js:39
msgctxt "widget"
msgid "Not available anymore"
msgstr ""
msgstr "Již není k dispozici"
#: pretix/static/pretixpresale/js/widget/widget.js:40
#, fuzzy
#| msgctxt "widget"
#| msgid "currently available: %s"
msgctxt "widget"
msgid "Currently not available"
msgstr "aktuálně k dispozici: %s"
msgstr "Momentálně není k dispozici."
#: pretix/static/pretixpresale/js/widget/widget.js:42
#, javascript-format
@@ -942,12 +928,9 @@ msgid "Open ticket shop"
msgstr "Obchod vstupenek otevřit"
#: pretix/static/pretixpresale/js/widget/widget.js:48
#, fuzzy
#| msgctxt "widget"
#| msgid "Resume checkout"
msgctxt "widget"
msgid "Checkout"
msgstr "Obnovit checkout"
msgstr "Checkout"
#: pretix/static/pretixpresale/js/widget/widget.js:49
msgctxt "widget"
@@ -1009,20 +992,14 @@ msgid "Continue"
msgstr "Pokračovat"
#: pretix/static/pretixpresale/js/widget/widget.js:61
#, fuzzy
#| msgctxt "widget"
#| msgid "See variations"
msgctxt "widget"
msgid "Show variants"
msgstr "Zobrazit možnosti"
#: pretix/static/pretixpresale/js/widget/widget.js:62
#, fuzzy
#| msgctxt "widget"
#| msgid "See variations"
msgctxt "widget"
msgid "Hide variants"
msgstr "Zobrazit možnosti"
msgstr "Skrýt možnosti"
#: pretix/static/pretixpresale/js/widget/widget.js:63
msgctxt "widget"
@@ -1110,31 +1087,31 @@ msgstr "Ne"
#: pretix/static/pretixpresale/js/widget/widget.js:81
msgid "Monday"
msgstr ""
msgstr "Pondělí"
#: pretix/static/pretixpresale/js/widget/widget.js:82
msgid "Tuesday"
msgstr ""
msgstr "Úterý"
#: pretix/static/pretixpresale/js/widget/widget.js:83
msgid "Wednesday"
msgstr ""
msgstr "Středa"
#: pretix/static/pretixpresale/js/widget/widget.js:84
msgid "Thursday"
msgstr ""
msgstr "Čtvrtek"
#: pretix/static/pretixpresale/js/widget/widget.js:85
msgid "Friday"
msgstr ""
msgstr "Pátek"
#: pretix/static/pretixpresale/js/widget/widget.js:86
msgid "Saturday"
msgstr ""
msgstr "Sobota"
#: pretix/static/pretixpresale/js/widget/widget.js:87
msgid "Sunday"
msgstr ""
msgstr "Neděle"
#: pretix/static/pretixpresale/js/widget/widget.js:90
msgid "January"
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-28 11:06+0000\n"
"PO-Revision-Date: 2025-04-14 23:00+0000\n"
"PO-Revision-Date: 2025-05-17 18:00+0000\n"
"Last-Translator: Patrick Chilton <chpatrick@gmail.com>\n"
"Language-Team: Hungarian <https://translate.pretix.eu/projects/pretix/pretix/"
"hu/>\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.10.4\n"
"X-Generator: Weblate 5.11.4\n"
#: pretix/_base_settings.py:87
msgid "English"
@@ -14670,7 +14670,7 @@ msgstr "A kiválasztott \"{seat}\" ülés nem elérhető."
#: pretix/control/logdisplay.py:406 pretix/control/views/orders.py:1573
#: pretix/presale/views/order.py:1047
msgid "The order has been canceled."
msgstr ""
msgstr "A megrendelés sztornózva lett."
#: pretix/control/logdisplay.py:414
#, python-brace-format
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -8,17 +8,17 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-28 11:08+0000\n"
"PO-Revision-Date: 2019-08-27 08:00+0000\n"
"Last-Translator: Bostjan Marusic <bostjan@brokenbones.si>\n"
"Language-Team: Slovenian <https://translate.pretix.eu/projects/pretix/pretix-"
"js/sl/>\n"
"PO-Revision-Date: 2025-05-16 17:00+0000\n"
"Last-Translator: bstramsek <stramsek.borut+pretix-translate@gmail.com>\n"
"Language-Team: Slovenian <https://translate.pretix.eu/projects/pretix/"
"pretix-js/sl/>\n"
"Language: sl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || "
"n%100==4 ? 2 : 3;\n"
"X-Generator: Weblate 3.5.1\n"
"X-Generator: Weblate 5.11.4\n"
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
@@ -32,7 +32,7 @@ msgstr "Komentar:"
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:34
msgid "PayPal"
msgstr ""
msgstr "PayPal"
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:35
msgid "Venmo"
@@ -1,5 +1,4 @@
{% load i18n %}
{% load icon %}
{% load eventurl %}
{% if item.current_unavailability_reason == 'require_voucher' %}
@@ -21,15 +20,14 @@
{% elif avail <= 10 %}
<div class="col-md-2 col-sm-3 col-xs-6 availability-box gone">
{% if price or original_price %}
<strong>{% icon "ban" %} {% trans "SOLD OUT" %}</strong>
<strong>{% trans "SOLD OUT" %}</strong>
{% else %}
<strong>{% icon "ban" %} {% trans "FULLY BOOKED" %}</strong>
<strong>{% trans "FULLY BOOKED" %}</strong>
{% endif %}
</span>
{% if allow_waitinglist and item.allow_waitinglist %}
<br/>
<a href="{% eventurl event "presale:event.waitinglist" cart_namespace=cart_namespace|default_if_none:"" %}?item={{ item.pk }}{% if var %}&var={{ var.pk }}{% endif %}{% if subevent %}&subevent={{ subevent.pk }}{% endif %}" class="btn btn-default btn-xs">
{% icon "plus-circle" %}
<a href="{% eventurl event "presale:event.waitinglist" cart_namespace=cart_namespace|default_if_none:"" %}?item={{ item.pk }}{% if var %}&var={{ var.pk }}{% endif %}{% if subevent %}&subevent={{ subevent.pk }}{% endif %}">
<span class="fa fa-plus-circle" aria-hidden="true"></span>
{% trans "Waiting list" %}
</a>
{% endif %}
@@ -492,15 +492,21 @@
<div class="row">
<div class="col-md-12">
{% if not cart.is_ordered %}
<p class="text-muted" id="cart-deadline" data-expires="{{ cart.first_expiry|date:"Y-m-d H:i:sO" }}">
{% if cart.minutes_left > 0 or cart.seconds_left > 0 %}
{% blocktrans trimmed with minutes=cart.minutes_left %}
The items in your cart are reserved for you for {{ minutes }} minutes.
{% endblocktrans %}
{% else %}
{% trans "The items in your cart are no longer reserved for you. You can still complete your order as long as theyre available." %}
{% endif %}
</p>
<form class="text-muted"
method="post" data-asynctask action="{% eventurl request.event "presale:event.cart.extend" cart_namespace=cart_namespace %}">
{% csrf_token %}
<span id="cart-deadline" data-expires="{{ cart.first_expiry|date:"Y-m-d H:i:sO" }}">
{% if cart.minutes_left > 0 or cart.seconds_left > 0 %}
{% blocktrans trimmed with minutes=cart.minutes_left %}
The items in your cart are reserved for you for {{ minutes }} minutes.
{% endblocktrans %}
{% else %}
{% trans "The items in your cart are no longer reserved for you. You can still complete your order as long as theyre available." %}
{% endif %}
</span>
<button class="btn btn-link" type="submit" id="cart-extend-button">
<i class="fa fa-refresh" aria-hidden="true"></i> {% trans "Extend" %}</button>
</form>
{% else %}
<p class="sr-only" id="cart-description">{% trans "Overview of your ordered products." %}</p>
{% endif %}
@@ -1,5 +1,4 @@
{% load i18n %}
{% load icon %}
{% load l10n %}
{% load eventurl %}
{% load money %}
@@ -83,9 +82,9 @@
{% if not event.settings.show_variations_expanded %}
{% if item.best_variation_availability <= 10 %}
{% if not item.min_price %}
<strong class="gone">{% icon "ban" %} {% trans "FULLY BOOKED" %}</strong>
<strong class="gone">{% trans "FULLY BOOKED" %}</strong>
{% else %}
<strong class="gone">{% icon "ban" %} {% trans "SOLD OUT" %}</strong>
<strong class="gone">{% trans "SOLD OUT" %}</strong>
{% endif %}
{% if allow_waitinglist and item.allow_waitinglist %}
<br/>
@@ -7,6 +7,8 @@
{% load thumb %}
{% load eventsignal %}
{% load rich_text %}
{% load icon %}
{% load dialog %}
{% block title %}
{% if "year" in request.GET %}
@@ -240,6 +242,13 @@
</div>
{% endif %}
</form>
{% if ev.presale_is_running and display_add_to_cart %}
{% trans "You didnt select any ticket." as label_nothing_to_add %}
{% trans "Please tick a checkbox or enter a quantity for one of the ticket types to add to the cart." as description_nothing_to_add %}
{% dialog "dialog-nothing-to-add" label_nothing_to_add description_nothing_to_add icon="exclamation-circle" %}
<p class="modal-card-confirm"><button class="btn btn-primary">{% trans "OK" %}</button></p>
{% enddialog %}
{% endif %}
{% endif %}
{% endif %}
</main>
@@ -2,6 +2,8 @@
{% load rich_text %}
{% load safelink %}
{% load escapejson %}
{% load icon %}
{% load dialog %}
<div id="ajaxerr">
</div>
<div id="popupmodal" hidden aria-live="polite">
@@ -50,93 +52,74 @@
{{ cookie_consent_from_widget|json_script:"cookie-consent-from-widget" }}
{% endif %}
{% if cookie_providers %}
<div id="cookie-consent-modal" aria-live="polite">
<div class="modal-card">
<div class="modal-card-content">
<h3 id="cookie-consent-modal-label"></h3>
<div id="cookie-consent-modal-description">
<form class="form-horizontal">
{% with request.event|default:request.organizer as sh %}
<h3>{{ sh.settings.cookie_consent_dialog_title }}</h3>
{{ sh.settings.cookie_consent_dialog_text|rich_text }}
{% if sh.settings.cookie_consent_dialog_text_secondary %}
<div class="text-muted">
{{ sh.settings.cookie_consent_dialog_text_secondary|rich_text }}
</div>
{% endif %}
<details id="cookie-consent-details">
<summary>
<span class="fa fa-fw chevron"></span>
{% trans "Adjust settings in detail" %}
</summary>
<div class="checkbox">
<label>
<input type="checkbox" disabled checked="" aira-describedby="cookie-consent-checkbox-required-description">
{% trans "Required cookies" %}
</label>
</div>
<div class="help-block" id="cookie-consent-checkbox-required-description">
<p>{% trans "Functional cookies (e.g. shopping cart, login, payment, language preference) and technical cookies (e.g. security purposes)" %}</p>
</div>
{% for cp in cookie_providers %}
<div class="checkbox">
<label>
<input type="checkbox" name="{{ cp.identifier }}" aira-describedby="cookie-consent-checkbox-{{ cp.identifier }}-description">
{{ cp.provider_name }}
</label>
</div>
<div class="help-block" id="cookie-consent-checkbox-{{ cp.identifier }}-description">
<p>
{% for c in cp.usage_classes %}
{% if forloop.counter0 > 0 %}&middot; {% endif %}
{% if c.value == 1 %}
{% trans "Functionality" context "cookie_usage" %}
{% elif c.value == 2 %}
{% trans "Analytics" context "cookie_usage" %}
{% elif c.value == 3 %}
{% trans "Marketing" context "cookie_usage" %}
{% elif c.value == 4 %}
{% trans "Social features" context "cookie_usage" %}
{% endif %}
{% endfor %}
{% if cp.privacy_url %}
&middot;
<a href="{% safelink cp.privacy_url %}" target="_blank">
{% trans "Privacy policy" %}
</a>
{% endif %}
</p>
</div>
{% endfor %}
</details>
<div class="row">
<div class="col-xs-12 col-md-6">
<p>
<button type="button" class="btn btn-lg btn-block btn-primary" id="cookie-consent-button-no"
data-summary-text="{{ sh.settings.cookie_consent_dialog_button_no }}"
data-detail-text="{% trans "Save selection" %}">
{{ sh.settings.cookie_consent_dialog_button_no }}
</button>
</p>
</div>
<div class="col-xs-12 col-md-6">
<p>
<button type="button" class="btn btn-lg btn-block btn-primary" id="cookie-consent-button-yes">
{{ sh.settings.cookie_consent_dialog_button_yes }}
</button>
</p>
</div>
</div>
{% if sh.settings.privacy_url %}
<p class="text-center">
<a href="{% safelink sh.settings.privacy_url %}" target="_blank" rel="noopener">{% trans "Privacy policy" %}</a>
</p>
{% endif %}
{% endwith %}
<form>
{% with request.event|default:request.organizer as sh %}
{% dialog "cookie-consent-modal" sh.settings.cookie_consent_dialog_title sh.settings.cookie_consent_dialog_text|rich_text icon="shield" %}
{% if sh.settings.cookie_consent_dialog_text_secondary %}
<div class="text-muted">
{{ sh.settings.cookie_consent_dialog_text_secondary|rich_text }}
</div>
</div>
</div>
</div>
{% endif %}
<details id="cookie-consent-details">
<summary>
<span class="fa fa-fw chevron"></span>
{% trans "Adjust settings in detail" %}
</summary>
<div class="checkbox">
<label>
<input type="checkbox" disabled checked="" aira-describedby="cookie-consent-checkbox-required-description">
{% trans "Required cookies" %}
</label>
</div>
<div class="help-block" id="cookie-consent-checkbox-required-description">
<p>{% trans "Functional cookies (e.g. shopping cart, login, payment, language preference) and technical cookies (e.g. security purposes)" %}</p>
</div>
{% for cp in cookie_providers %}
<div class="checkbox">
<label>
<input type="checkbox" name="{{ cp.identifier }}" aira-describedby="cookie-consent-checkbox-{{ cp.identifier }}-description">
{{ cp.provider_name }}
</label>
</div>
<div class="help-block" id="cookie-consent-checkbox-{{ cp.identifier }}-description">
<p>
{% for c in cp.usage_classes %}
{% if forloop.counter0 > 0 %}&middot; {% endif %}
{% if c.value == 1 %}
{% trans "Functionality" context "cookie_usage" %}
{% elif c.value == 2 %}
{% trans "Analytics" context "cookie_usage" %}
{% elif c.value == 3 %}
{% trans "Marketing" context "cookie_usage" %}
{% elif c.value == 4 %}
{% trans "Social features" context "cookie_usage" %}
{% endif %}
{% endfor %}
{% if cp.privacy_url %}
&middot;
<a href="{% safelink cp.privacy_url %}" target="_blank">
{% trans "Privacy policy" %}
</a>
{% endif %}
</p>
</div>
{% endfor %}
</details>
<p class="modal-card-confirm modal-card-confirm-spread">
<button class="btn btn-lg btn-default" id="cookie-consent-button-no" value="no" autofocus="true"
data-summary-text="{{ sh.settings.cookie_consent_dialog_button_no }}"
data-detail-text="{% trans "Save selection" %}">
{{ sh.settings.cookie_consent_dialog_button_no }}
</button>
<button class="btn btn-lg btn-primary" id="cookie-consent-button-yes" value="yes">
{{ sh.settings.cookie_consent_dialog_button_yes }}
</button>
</p>
{% if sh.settings.privacy_url %}
<p class="text-center">
<small><a href="{% safelink sh.settings.privacy_url %}" target="_blank" rel="noopener">{% trans "Privacy policy" %}</a></small>
</p>
{% endif %}
{% enddialog %}
{% endwith %}
{% endif %}
{% endif %}
@@ -49,7 +49,7 @@
<div class="event-list full-width-list alternating-rows">
{% for e in events %}{% eventurl e "presale:event.index" as url %}
<article class="row" aria-labelledby="event-{{ e.pk }}-label" aria-describedby="event-{{ e.pk }}-desc">
<h3 class="col-md-4 col-xs-12"><a href="{{ url }}" id="event-{{ e.pk }}-label">{{ e.name }}</a></h3>
<h3 class="col-md-4 col-xs-12"><a href="{{ url }}" id="event-{{ e.pk }}-label" class="no-underline">{{ e.name }}</a></h3>
<p class="col-md-3 col-xs-12" id="event-{{ e.pk }}-desc">
{% if e.settings.show_dates_on_frontpage %}
{% if e.has_subevents %}
+1
View File
@@ -56,6 +56,7 @@ frame_wrapped_urls = [
re_path(r'^cart/remove$', pretix.presale.views.cart.CartRemove.as_view(), name='event.cart.remove'),
re_path(r'^cart/voucher$', pretix.presale.views.cart.CartApplyVoucher.as_view(), name='event.cart.voucher'),
re_path(r'^cart/clear$', pretix.presale.views.cart.CartClear.as_view(), name='event.cart.clear'),
re_path(r'^cart/extend$', pretix.presale.views.cart.CartExtendReservation.as_view(), name='event.cart.extend'),
re_path(r'^cart/answer/(?P<answer>[^/]+)/$',
pretix.presale.views.cart.AnswerDownload.as_view(),
name='event.cart.download.answer'),
+15 -1
View File
@@ -62,7 +62,7 @@ from pretix.base.models import (
)
from pretix.base.services.cart import (
CartError, add_items_to_cart, apply_voucher, clear_cart, error_messages,
remove_cart_position,
extend_cart_reservation, remove_cart_position,
)
from pretix.base.timemachine import time_machine_now
from pretix.base.views.tasks import AsyncAction
@@ -537,6 +537,20 @@ class CartClear(EventViewMixin, CartActionMixin, AsyncAction, View):
request.sales_channel.identifier, time_machine_now(default=None))
@method_decorator(allow_frame_if_namespaced, 'dispatch')
class CartExtendReservation(EventViewMixin, CartActionMixin, AsyncAction, View):
task = extend_cart_reservation
known_errortypes = ['CartError']
def get_success_message(self, value):
if value > 0:
return _('Your cart timeout was extended.')
def post(self, request, *args, **kwargs):
return self.do(self.request.event.id, get_or_create_cart_id(self.request), translation.get_language(),
request.sales_channel.identifier, time_machine_now(default=None))
@method_decorator(allow_cors_if_namespaced, 'dispatch')
@method_decorator(allow_frame_if_namespaced, 'dispatch')
@method_decorator(iframe_entry_view_wrapper, 'dispatch')
Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

+2 -2
View File
@@ -49,7 +49,7 @@ html.rtl {
}
input[lang=ar], textarea[lang=ar], div[lang=ar], pre[lang=ar],
input[lang=hw], textarea[lang=hw], div[lang=hw], pre[lang=hw] {
input[lang=he], textarea[lang=he], div[lang=he], pre[lang=he] {
/* Keep list of languages in sync with pretix._base_settings.LANGUAGES_RTL */
direction: rtl;
}
}
@@ -262,3 +262,95 @@ svg.svg-icon {
@include table-row-variant('info', var(--pretix-brand-info-success-lighten-30), var(--pretix-brand-info-success-lighten-25));
@include table-row-variant('warning', var(--pretix-brand-warning-lighten-40), var(--pretix-brand-warning-lighten-35));
@include table-row-variant('danger', var(--pretix-brand-danger-lighten-30), var(--pretix-brand-danger-lighten-25));
dialog {
border: none;
width: 80%;
max-width: 43em;
padding: 0;
box-shadow: 0 7px 14px 0 rgba(78, 50, 92, 0.1),0 3px 6px 0 rgba(0,0,0,.07);
background: white;
border-radius: $border-radius-large;
opacity: 0;
transition: opacity .5s allow-discrete;
.modal-card {
display: flex;
flex-direction: column;
align-content: stretch;
}
.modal-card-icon {
background: $brand-primary;
font-size: 2em;
color: white;
text-align: center;
padding: 3px;
}
.modal-card-content {
padding: 1.5em;
}
.modal-card-content>*:last-child {
margin-bottom: 0;
}
.modal-card-content>*:first-child {
margin-top: 0;
}
.modal-card-confirm {
margin-top: 2em;
display: flex;
justify-content: flex-end;
gap: 1em;
align-items: center;
}
.modal-card-confirm-spread {
justify-content: space-between;
}
}
dialog::backdrop {
background-color: rgba(255, 255, 255, .5);
opacity: 0;
transition: opacity .5s allow-discrete;
}
dialog[open], dialog[open]::backdrop {
opacity: 1;
}
@starting-style {
dialog[open], dialog[open]::backdrop {
opacity: 0;
}
}
@media screen and (min-width: $screen-sm-min) {
dialog {
.modal-card:has(.modal-card-icon) {
flex-direction: row;
}
.modal-card-content {
padding: 2em;
}
.modal-card-icon {
font-size: 4em;
padding: 6px 16px;
}
}
}
.shake-once {
animation: shake .2s;
transform: translate3d(0, 0, 0);
backface-visibility: hidden;
}
@keyframes shake {
0% { transform: skewX(0deg); }
20% { transform: skewX(-5deg); }
40% { transform: skewX(5deg); }
60% { transform: skewX(-5deg); }
80% { transform: skewX(5deg); }
100% { transform: skewX(0deg); }
}
@@ -160,7 +160,7 @@ pre[lang=ht], input[lang=ht], textarea[lang=ht], div[lang=ht] { background-image
pre[lang=hu], input[lang=hu], textarea[lang=hu], div[lang=hu] { background-image: url(static('pretixbase/img/flags/hu.png')); }
pre[lang=id], input[lang=id], textarea[lang=id], div[lang=id] { background-image: url(static('pretixbase/img/flags/id.png')); }
pre[lang=ie], input[lang=ie], textarea[lang=ie], div[lang=ie] { background-image: url(static('pretixbase/img/flags/ie.png')); }
pre[lang=il], input[lang=il], textarea[lang=il], div[lang=il] { background-image: url(static('pretixbase/img/flags/il.png')); }
pre[lang=he], input[lang=he], textarea[lang=he], div[lang=he] { background-image: url(static('pretixbase/img/flags/il.png')); }
pre[lang=in], input[lang=in], textarea[lang=in], div[lang=in] { background-image: url(static('pretixbase/img/flags/in.png')); }
pre[lang=io], input[lang=io], textarea[lang=io], div[lang=io] { background-image: url(static('pretixbase/img/flags/io.png')); }
pre[lang=iq], input[lang=iq], textarea[lang=iq], div[lang=iq] { background-image: url(static('pretixbase/img/flags/iq.png')); }
@@ -306,3 +306,4 @@ pre[lang=za], input[lang=za], textarea[lang=za], div[lang=za] { background-image
pre[lang=zm], input[lang=zm], textarea[lang=zm], div[lang=zm] { background-image: url(static('pretixbase/img/flags/zm.png')); }
pre[lang=zw], input[lang=zw], textarea[lang=zw], div[lang=zw] { background-image: url(static('pretixbase/img/flags/zw.png')); }
pre[lang=en], input[lang=en], textarea[lang=en], div[lang=en] { background-image: url(static('pretixbase/img/flags/gb.png')); }
pre[lang=eu], input[lang=eu], textarea[lang=eu], div[lang=eu] { background-image: url(static('pretixbase/img/flags/basque.png')); }
@@ -55,6 +55,7 @@ var cart = {
pad(diff_minutes.toString(), 2) + ':' + pad(diff_seconds.toString(), 2)
);
}
$("#cart-extend-button").toggle(diff_minutes < 3);
},
init: function () {
@@ -6,7 +6,7 @@ $(function () {
var storage_key = $("#cookie-consent-storage-key").text();
var widget_consent = $("#cookie-consent-from-widget").text();
var consent_checkboxes = $("#cookie-consent-details input[type=checkbox][name]");
var consent_modal = $("#cookie-consent-modal");
var consent_modal = document.getElementById("cookie-consent-modal");
function update_consent(consent, sessionOnly) {
if (storage_key && window.sessionStorage && sessionOnly) {
@@ -108,25 +108,32 @@ $(function () {
_set_button_text();
if (show_dialog) {
// We use .css() instead of .show() because of some weird issue that only occurs in Firefox
// and only within the widget.
consent_modal.css("display", "block");
consent_modal.showModal();
consent_modal.addEventListener("cancel", function() {
// Dialog was initially shown, interpret Escape as „do not consent to new providers“
var consent = {};
consent_checkboxes.each(function () {
consent[this.name] = storage_val[this.name] || false;
});
update_consent(consent, false);
}, {once : true});
}
$("#cookie-consent-button-yes, #cookie-consent-button-no").on("click", function () {
consent_modal.hide();
consent_modal.addEventListener("close", function () {
if (!consent_modal.returnValue) {// ESC, do not save
return;
}
var consent = {};
var consent_all = this.id == "cookie-consent-button-yes";
var consent_all = consent_modal.returnValue == "yes";
consent_checkboxes.each(function () {
consent[this.name] = this.checked = consent_all || this.checked;
});
if (consent_all) _set_button_text();
// Always save explicit consent to permanent storage
update_consent(consent, false);
});
consent_checkboxes.on("change", _set_button_text);
$("#cookie-consent-reopen").on("click", function (e) {
consent_modal.show()
consent_modal.showModal()
e.preventDefault()
return true
})
+21 -26
View File
@@ -390,6 +390,13 @@ $(function () {
sessionStorage.removeItem('scrollpos');
}
$("dialog").on("mousedown", function (e) {
if (e.target == this) {
// dialog has no padding, so this triggers only onclick on backdrop
this.close();
}
});
$(".accordion-radio").click(function() {
var $input = $("input", this);
if (!$input.prop("checked")) $input.prop('checked', true).trigger("change");
@@ -478,33 +485,21 @@ $(function () {
sessionStorage.setItem('scrollpos', window.scrollY);
});
}
var update_cart_form = function () {
var is_enabled = $(".product-row input[type=checkbox]:checked, .variations input[type=checkbox]:checked, .product-row input[type=radio]:checked, .variations input[type=radio]:checked").length;
if (!is_enabled) {
$(".input-item-count").each(function () {
if ($(this).val() && $(this).val() !== "0") {
is_enabled = true;
}
});
$(".input-seat-selection option").each(function() {
if ($(this).val() && $(this).val() !== "" && $(this).prop('selected')) {
is_enabled = true;
}
});
$("form:has(#btn-add-to-cart)").on("submit", function(e) {
if (
(this.classList.contains("has-seating") && this.querySelector("pretix-seating-checkout-button button")) ||
this.querySelector("input[type=checkbox]:checked") ||
[...this.querySelectorAll(".input-item-count[type=text]")].some(input => input.value && input.value !== "0") // TODO: seating hat noch einen seating-dummy-item-count, das ist Mist!
) {
// okay, let the submit-event bubble to async-task
return;
}
if (!is_enabled && (!$(".has-seating").length || $("#seating-dummy-item-count").length)) {
$("#btn-add-to-cart").prop("disabled", !is_enabled).popover({
'content': function () { return gettext("Please enter a quantity for one of the ticket types.") },
'placement': 'top',
'trigger': 'hover focus'
});
} else {
$("#btn-add-to-cart").prop("disabled", false).popover("destroy")
}
};
update_cart_form();
$(".product-row input[type=checkbox], .variations input[type=checkbox], .product-row input[type=radio], .variations input[type=radio], .input-item-count, .input-seat-selection")
.on("change mouseup keyup", update_cart_form);
e.preventDefault();
e.stopPropagation();
document.querySelector("#dialog-nothing-to-add").showModal();
});
$(".table-calendar td.has-events").click(function () {
var $grid = $(this).closest("[role='grid']");
@@ -471,7 +471,7 @@ Vue.component('variation', {
// Variation description
+ '<div class="pretix-widget-item-info-col">'
+ '<div class="pretix-widget-item-title-and-description">'
+ '<strong :id="variation_label_id" class="pretix-widget-item-title">{{ variation.value }}</strong>'
+ '<strong :id="variation_label_id" class="pretix-widget-item-title" role="heading" v-bind:aria-level="headingLevel">{{ variation.value }}</strong>'
+ '<div :id="variation_desc_id" class="pretix-widget-item-description" v-if="variation.description" v-html="variation.description"></div>'
+ '<p class="pretix-widget-item-meta" '
+ ' v-if="!variation.has_variations && variation.avail[1] !== null && variation.avail[0] === 100">'
@@ -500,6 +500,7 @@ Vue.component('variation', {
props: {
variation: Object,
item: Object,
category: Object,
},
computed: {
orig_price: function () {
@@ -523,6 +524,9 @@ Vue.component('variation', {
aria_labelledby: function () {
return [this.variation_label_id, this.variation_price_id].join(" ");
},
headingLevel: function () {
return this.category.name ? '5' : '4';
},
}
});
Vue.component('item', {
@@ -533,12 +537,12 @@ Vue.component('item', {
+ '<div class="pretix-widget-item-info-col">'
+ '<a :href="item.picture_fullsize" v-if="item.picture" class="pretix-widget-item-picture-link" @click.prevent.stop="lightbox"><img :src="item.picture" class="pretix-widget-item-picture" :alt="picture_alt_text"></a>'
+ '<div class="pretix-widget-item-title-and-description">'
+ '<a v-if="item.has_variations && show_toggle" :id="item_label_id" class="pretix-widget-item-title" :href="\'#\' + item.id + \'-variants\'"'
+ '<a v-if="item.has_variations && show_toggle" :id="item_label_id" role="heading" v-bind:aria-level="headingLevel" class="pretix-widget-item-title" :href="\'#\' + item.id + \'-variants\'"'
+ ' @click.prevent.stop="expand"'
+ '>'
+ '{{ item.name }}'
+ '</a>'
+ '<strong v-else class="pretix-widget-item-title" :id="item_label_id">{{ item.name }}</strong>'
+ '<strong v-else class="pretix-widget-item-title" :id="item_label_id" role="heading" v-bind:aria-level="headingLevel">{{ item.name }}</strong>'
+ '<div class="pretix-widget-item-description" :id="item_desc_id" v-if="item.description" v-html="item.description"></div>'
+ '<p class="pretix-widget-item-meta" v-if="item.order_min && item.order_min > 1">'
+ '<small>{{ min_order_str }}</small>'
@@ -572,13 +576,14 @@ Vue.component('item', {
// Variations
+ '<div :class="varClasses" v-if="item.has_variations" :id="item.id + \'-variants\'" ref="variations">'
+ '<variation v-for="variation in item.variations" :variation="variation" :item="item" :key="variation.id">'
+ '<variation v-for="variation in item.variations" :variation="variation" :item="item" :category="category" :key="variation.id">'
+ '</variation>'
+ '</div>'
+ '</div>'),
props: {
item: Object,
category: Object,
},
data: function () {
return {
@@ -636,6 +641,9 @@ Vue.component('item', {
picture_alt_text: function () {
return django.interpolate(strings["image_of"], [this.item.name]);
},
headingLevel: function () {
return this.category.name ? '4' : '3';
},
item_label_id: function () {
return this.$root.html_id + '-item-label-' + this.item.id;
},
@@ -687,7 +695,7 @@ Vue.component('category', {
+ '<div class="pretix-widget-category-description" v-if="category.description" v-html="category.description">'
+ '</div>'
+ '<div class="pretix-widget-category-items">'
+ '<item v-for="item in category.items" :item="item" :key="item.id"></item>'
+ '<item v-for="item in category.items" :category="category" :item="item" :key="item.id"></item>'
+ '</div>'
+ '</div>'),
props: {
@@ -1002,7 +1010,7 @@ Vue.component('pretix-widget-event-form', {
// Event name
+ '<div class="pretix-widget-event-header" v-if="display_event_info">'
+ '<strong>{{ $root.name }}</strong>'
+ '<strong role="heading" aria-level="2">{{ $root.name }}</strong>'
+ '</div>'
// Date range
@@ -23,7 +23,7 @@
text-align: center;
&.gone, .gone {
color: $brand-danger;
color: $alert-danger-text;
}
&.unavailable, .unavailable {
color: $alert-warning-text;
@@ -76,6 +76,7 @@ html {
clip: auto;
}
#skip-to-main {
z-index: 9999;
/* padding is needed to make focus-outline visible */
padding: 8px;
background-color: inherit;
@@ -156,6 +157,7 @@ button:focus, a:focus, .btn:focus, summary:focus, div:focus,
button:active:focus, a:active:focus, .btn:active:focus, summary:active:focus, div:active:focus,
button.active:focus, a.active:focus, .btn.active:focus,
input:focus, .form-control:focus, .btn-checkbox:has(input:focus),
input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus,
.input-item-count-group:has(input:focus), .input-group-price:has(input:focus) {
outline: 2px solid $link-hover-color;
outline-offset: 2px;
@@ -289,7 +291,7 @@ body.loading .container {
font-size: 120px;
color: $brand-primary;
}
#loadingmodal, #ajaxerr, #cookie-consent-modal, #popupmodal {
#loadingmodal, #ajaxerr, #popupmodal {
position: fixed;
top: 0;
left: 0;
@@ -359,7 +361,7 @@ body.loading .container {
}
}
@media (max-width: 700px) {
#loadingmodal, #ajaxerr, #cookie-consent-modal, #popupmodal {
#loadingmodal, #ajaxerr, #popupmodal {
.modal-card {
margin: 25px auto 0;
max-height: calc(100vh - 50px - 20px);
File diff suppressed because it is too large Load Diff