mirror of
https://github.com/pretix/pretix.git
synced 2025-12-12 04:42:28 +00:00
Compare commits
7 Commits
order-roun
...
a11y-commo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
370d0438e4 | ||
|
|
0eee35be86 | ||
|
|
0bc09a3583 | ||
|
|
d2ebbcc4d9 | ||
|
|
d3368fe9b6 | ||
|
|
0aa1ea73f1 | ||
|
|
cf17b63a83 |
@@ -1,6 +1,7 @@
|
|||||||
{% load compress %}
|
{% load compress %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load icon %}
|
||||||
{% load safelink %}
|
{% load safelink %}
|
||||||
{% load statici18n %}
|
{% load statici18n %}
|
||||||
{% load thumb %}
|
{% load thumb %}
|
||||||
@@ -47,6 +48,38 @@
|
|||||||
<nav id="skip-to-main" role="navigation" aria-label="{% trans "Skip link" context "skip-to-main-nav" %}" class="sr-only on-focus-visible">
|
<nav id="skip-to-main" role="navigation" aria-label="{% trans "Skip link" context "skip-to-main-nav" %}" class="sr-only on-focus-visible">
|
||||||
<p><a href="#content">{% trans "Skip to main content" %}</a></p>
|
<p><a href="#content">{% trans "Skip to main content" %}</a></p>
|
||||||
</nav>
|
</nav>
|
||||||
|
{% comment %}
|
||||||
|
<dialog> needs to be available onload and role-attribute cannot be changed dynamically.
|
||||||
|
Therefore we need two dialogs, one normal (e.g. for status info like "loading") and one
|
||||||
|
alertdialog with a confirm-button.
|
||||||
|
Note: dialog[aria-describedby] is not read out on VoiceOver, so we add both label and
|
||||||
|
description to aria-labelledby.
|
||||||
|
{% endcomment %}
|
||||||
|
<dialog id="dialog-info" aria-labelledby="dialog-info-label dialog-info-description">
|
||||||
|
<div class="modal-card">
|
||||||
|
<div class="modal-card-icon">
|
||||||
|
{% icon "cog big-rotating-icon" %}
|
||||||
|
</div>
|
||||||
|
<div class="modal-card-content">
|
||||||
|
<h2 id="dialog-info-label">Hier die Überschrift</h2>
|
||||||
|
<p id="dialog-info-description">Hier kommt der Text. Danach der Status-Absatz.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
<dialog id="dialog-alert" role="alertdialog" aria-labelledby="dialog-alert-label dialog-alert-description">
|
||||||
|
<div class="modal-card">
|
||||||
|
<div class="modal-card-icon">
|
||||||
|
{% icon "cog big-rotating-icon" %}
|
||||||
|
</div>
|
||||||
|
<div class="modal-card-content">
|
||||||
|
<h2 id="dialog-alert-label">Hier die Überschrift</h2>
|
||||||
|
<p id="dialog-alert-description"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<form method="dialog" class="text-right">
|
||||||
|
<button class="btn btn-primary">OK</button>
|
||||||
|
</form>
|
||||||
|
</dialog>
|
||||||
<header>
|
<header>
|
||||||
{% if ie_deprecation_warning %}
|
{% if ie_deprecation_warning %}
|
||||||
<div class="old-browser-warning">
|
<div class="old-browser-warning">
|
||||||
|
|||||||
@@ -117,7 +117,6 @@ function async_task_callback(data, jqXHR, status) {
|
|||||||
$("body").data('ajaxing', false);
|
$("body").data('ajaxing', false);
|
||||||
if (data.redirect) {
|
if (data.redirect) {
|
||||||
if (async_task_is_download && data.success) {
|
if (async_task_is_download && data.success) {
|
||||||
waitingDialog.hide();
|
|
||||||
if (location.href.indexOf("async_id") !== -1) {
|
if (location.href.indexOf("async_id") !== -1) {
|
||||||
history.replaceState({}, "pretix", async_task_old_url);
|
history.replaceState({}, "pretix", async_task_old_url);
|
||||||
}
|
}
|
||||||
@@ -131,22 +130,21 @@ function async_task_callback(data, jqXHR, status) {
|
|||||||
|
|
||||||
if (async_task_is_long) {
|
if (async_task_is_long) {
|
||||||
if (data.started) {
|
if (data.started) {
|
||||||
$("#loadingmodal p.status").text(gettext(
|
window.pretix.dialog.open({
|
||||||
'Your request is currently being processed. Depending on the size of your event, this might take up to ' +
|
label: gettext("Your request is currently being processed."),
|
||||||
'a few minutes.'
|
message: gettext("Depending on the size of the event, this might take up to a few minutes."),
|
||||||
));
|
});
|
||||||
} else {
|
} else {
|
||||||
$("#loadingmodal p.status").text(gettext(
|
window.pretix.dialog.open({
|
||||||
'Your request has been queued on the server and will soon be ' +
|
label: gettext("Your request has been queued on the server."),
|
||||||
'processed.'
|
message: gettext("It will soon be processed."),
|
||||||
));
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$("#loadingmodal p.status").text(gettext(
|
window.pretix.dialog.open({
|
||||||
'Your request arrived on the server but we still wait for it to be ' +
|
label: gettext("Your request arrived on the server but we still wait for it to be processed."),
|
||||||
'processed. If this takes longer than two minutes, please contact us or go ' +
|
message: gettext("If this takes longer than two minutes, please contact us or go back in your browser and try again."),
|
||||||
'back in your browser and try again.'
|
});
|
||||||
));
|
|
||||||
}
|
}
|
||||||
if (location.href.indexOf("async_id") === -1) {
|
if (location.href.indexOf("async_id") === -1) {
|
||||||
history.pushState({}, "Waiting", async_task_check_url.replace(/ajax=1/, ''));
|
history.pushState({}, "Waiting", async_task_check_url.replace(/ajax=1/, ''));
|
||||||
@@ -157,14 +155,18 @@ function async_task_error(jqXHR, textStatus, errorThrown) {
|
|||||||
"use strict";
|
"use strict";
|
||||||
$("body").data('ajaxing', false);
|
$("body").data('ajaxing', false);
|
||||||
if (textStatus === "timeout") {
|
if (textStatus === "timeout") {
|
||||||
alert(gettext("The request took too long. Please try again."));
|
window.pretix.dialog.open({
|
||||||
waitingDialog.hide();
|
label: gettext("The request took too long …"),
|
||||||
|
message: gettext("Please try again."),
|
||||||
|
confirm: true,
|
||||||
|
});
|
||||||
} else if (jqXHR.responseText.indexOf('<html') > 0) {
|
} else if (jqXHR.responseText.indexOf('<html') > 0) {
|
||||||
var respdom = $(jqXHR.responseText);
|
var respdom = $(jqXHR.responseText);
|
||||||
var c = respdom.filter('.container');
|
var c = respdom.filter('.container');
|
||||||
if (respdom.filter('form') && (respdom.filter('.has-error') || respdom.filter('.alert-danger'))) {
|
if (respdom.filter('form') && (respdom.filter('.has-error') || respdom.filter('.alert-danger'))) {
|
||||||
// This is a failed form validation, let's just use it
|
// This is a failed form validation, let's just use it
|
||||||
waitingDialog.hide();
|
window.pretix.dialog.close();
|
||||||
|
// TODO: we need to give feedback regarding the error; either focus an element with error or better output another dialog?
|
||||||
|
|
||||||
if (respdom.filter('#page-wrapper') && $('#page-wrapper').length) {
|
if (respdom.filter('#page-wrapper') && $('#page-wrapper').length) {
|
||||||
$("#page-wrapper").html(respdom.find("#page-wrapper").html());
|
$("#page-wrapper").html(respdom.find("#page-wrapper").html());
|
||||||
@@ -186,20 +188,32 @@ function async_task_error(jqXHR, textStatus, errorThrown) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else if (c.length > 0) {
|
} else if (c.length > 0) {
|
||||||
waitingDialog.hide();
|
window.pretix.dialog.open({
|
||||||
ajaxErrDialog.show(c.first().html());
|
label: gettext('An error occurred.'),
|
||||||
|
message: c.first().text(),
|
||||||
|
confirm: true,
|
||||||
|
});
|
||||||
|
//ajaxErrDialog.show(c.first().html());
|
||||||
} else {
|
} else {
|
||||||
waitingDialog.hide();
|
window.pretix.dialog.open({
|
||||||
alert(gettext('An error of type {code} occurred.').replace(/\{code\}/, jqXHR.status));
|
label: gettext('An error of type {code} occurred.').replace(/\{code\}/, jqXHR.status),
|
||||||
|
message: gettext("Please try again."),
|
||||||
|
confirm: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (jqXHR.status >= 400 && jqXHR.status < 500) {
|
if (jqXHR.status >= 400 && jqXHR.status < 500) {
|
||||||
waitingDialog.hide();
|
window.pretix.dialog.open({
|
||||||
alert(gettext('An error of type {code} occurred.').replace(/\{code\}/, jqXHR.status));
|
label: gettext('An error of type {code} occurred.').replace(/\{code\}/, jqXHR.status),
|
||||||
|
message: gettext("Please try again."),
|
||||||
|
confirm: true,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
waitingDialog.hide();
|
window.pretix.dialog.open({
|
||||||
alert(gettext('We currently cannot reach the server. Please try again. ' +
|
label: gettext('We currently cannot reach the server.'),
|
||||||
'Error code: {code}').replace(/\{code\}/, jqXHR.status));
|
message: gettext("Please try again. Error code: {code}").replace(/\{code\}/, jqXHR.status),
|
||||||
|
confirm: true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,21 +238,16 @@ $(function () {
|
|||||||
async_task_is_long = $(this).is("[data-asynctask-long]");
|
async_task_is_long = $(this).is("[data-asynctask-long]");
|
||||||
async_task_old_url = location.href;
|
async_task_old_url = location.href;
|
||||||
$("body").data('ajaxing', true);
|
$("body").data('ajaxing', true);
|
||||||
if ($(this).is("[data-asynctask-headline]")) {
|
|
||||||
waitingDialog.show($(this).attr("data-asynctask-headline"));
|
window.pretix.dialog.open({
|
||||||
} else {
|
label: this.getAttribute("data-asynctask-headline") || gettext("We are processing your request …"),
|
||||||
waitingDialog.show(gettext('We are processing your request …'));
|
message: (this.getAttribute("data-asynctask-text") || "") + gettext(
|
||||||
}
|
'We are currently sending your request to the server. If this takes longer ' +
|
||||||
if ($(this).is("[data-asynctask-text]")) {
|
'than one minute, please check your internet connection and then reload ' +
|
||||||
$("#loadingmodal p.text").text($(this).attr("data-asynctask-text")).show();
|
'this page and try again.'
|
||||||
} else {
|
),
|
||||||
$("#loadingmodal p.text").hide();
|
icon: 'cog',
|
||||||
}
|
});
|
||||||
$("#loadingmodal p.status").text(gettext(
|
|
||||||
'We are currently sending your request to the server. If this takes longer ' +
|
|
||||||
'than one minute, please check your internet connection and then reload ' +
|
|
||||||
'this page and try again.'
|
|
||||||
));
|
|
||||||
|
|
||||||
var action = this.action;
|
var action = this.action;
|
||||||
var formData = new FormData(this);
|
var formData = new FormData(this);
|
||||||
|
|||||||
@@ -380,12 +380,66 @@ function get_label_text_for_id(id) {
|
|||||||
}).text().trim();
|
}).text().trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
window.pretix = window.pretix || {};
|
||||||
|
window.pretix.dialog = {
|
||||||
|
close: function() {
|
||||||
|
$("#dialog-alert[open], #dialog-info[open]").each(function() {
|
||||||
|
this.close();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
open: function(opt) {
|
||||||
|
window.pretix.dialog.close();
|
||||||
|
|
||||||
|
const id = "dialog-" + (opt.confirm ? "alert" : "info");
|
||||||
|
const dialog = document.getElementById(id);
|
||||||
|
$("#" + id + "-label").text(opt.label);
|
||||||
|
$("#" + id + "-description").text(opt.message);
|
||||||
|
$(".modal-card-icon .fa", dialog).attr('class', 'fa fa-' + (opt.icon || "exclamation-triangle"));
|
||||||
|
if (opt.confirm) {
|
||||||
|
$("button", dialog).attr("value", opt.confirm.toString()).text(opt.confirm === true ? gettext("OK") : opt.confirm);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
dialog.addEventListener('close', function() {
|
||||||
|
resolve(dialog.returnValue);
|
||||||
|
}, { once: true });
|
||||||
|
|
||||||
|
dialog.showModal();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
$("body").removeClass("nojs");
|
$("body").removeClass("nojs");
|
||||||
moment.locale($("body").attr("data-datetimelocale"));
|
moment.locale($("body").attr("data-datetimelocale"));
|
||||||
|
|
||||||
|
$("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;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
window.pretix.dialog.open({
|
||||||
|
label: gettext("You have not selected any ticket."),
|
||||||
|
message: gettext("Please tick a checkbox or enter a quantity for one of the ticket types to add to the cart."),
|
||||||
|
icon: 'exclamation',
|
||||||
|
confirm: true,
|
||||||
|
}).then((result) => {
|
||||||
|
//console.log("returnValue is", result);
|
||||||
|
// TODO: should we focus the first input/checkbox/variants-button?
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
var scrollpos = sessionStorage ? sessionStorage.getItem('scrollpos') : 0;
|
var scrollpos = sessionStorage ? sessionStorage.getItem('scrollpos') : 0;
|
||||||
if (scrollpos) {
|
if (scrollpos) {
|
||||||
window.scrollTo(0, scrollpos);
|
window.scrollTo(0, scrollpos);
|
||||||
@@ -487,33 +541,6 @@ $(function () {
|
|||||||
this.form.submit();
|
this.form.submit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
|
|
||||||
$(".table-calendar td.has-events").click(function () {
|
$(".table-calendar td.has-events").click(function () {
|
||||||
var $grid = $(this).closest("[role='grid']");
|
var $grid = $(this).closest("[role='grid']");
|
||||||
|
|||||||
@@ -374,6 +374,47 @@ body.loading .container {
|
|||||||
-webkit-transition: opacity .5s ease-in-out;
|
-webkit-transition: opacity .5s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#dialog-info, #dialog-alert {
|
||||||
|
border: none;
|
||||||
|
background: white;
|
||||||
|
border-radius: $border-radius-large;
|
||||||
|
box-shadow: 0 7px 14px 0 rgba(78, 50, 92, 0.1),0 3px 6px 0 rgba(0,0,0,.07);
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
|
||||||
|
max-width: 32em;
|
||||||
|
max-height: calc(100vh - 100px);
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
|
||||||
|
&::backdrop {
|
||||||
|
background: rgba(255, 255, 255, .7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-card {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.modal-card-icon {
|
||||||
|
width: 150px;
|
||||||
|
text-align: center;
|
||||||
|
color: $brand-primary;
|
||||||
|
font-size: 120px;
|
||||||
|
}
|
||||||
|
.modal-card-content {
|
||||||
|
text-align: left;
|
||||||
|
h2 {
|
||||||
|
margin-top: 0;
|
||||||
|
font-size: 1.25em;
|
||||||
|
font-weight: bold;
|
||||||
|
color: $brand-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.typo-alert span[data-typosuggest] {
|
.typo-alert span[data-typosuggest] {
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|||||||
Reference in New Issue
Block a user