mirror of
https://github.com/pretix/pretix.git
synced 2026-10-05 19:54:42 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c795cff08a | ||
|
|
3726a355a7 | ||
|
|
e49ef5009b | ||
|
|
6d39d08085 | ||
|
|
3dd8cc5862 | ||
|
|
23e9ca8f34 | ||
|
|
e19afd39fb |
Generated
+15
-15
@@ -194,16 +194,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-array/node_modules/brace-expansion": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
|
||||
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
|
||||
"version": "5.0.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
|
||||
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-array/node_modules/minimatch": {
|
||||
@@ -1339,16 +1339,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
|
||||
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
|
||||
"version": "5.0.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
|
||||
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
|
||||
@@ -1697,9 +1697,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"version": "2.1.7",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.7.tgz",
|
||||
"integrity": "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2122,16 +2122,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/brace-expansion": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
|
||||
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
|
||||
"version": "5.0.12",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
|
||||
"integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "18 || 20 || >=22"
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/eslint-visitor-keys": {
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
# 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/>.
|
||||
#
|
||||
__version__ = "2026.8.0"
|
||||
__version__ = "2026.9.0.dev0"
|
||||
|
||||
@@ -1197,6 +1197,10 @@ class ItemAddOnForm(I18nModelForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['addon_category'].queryset = self.event.categories.all()
|
||||
self.fields['addon_category'].help_text = format_html('<a href="{}" data-iframe-dialog="true" data-iframe-dialog-target="<[name$=addon_category]" target="_blank">{}</a>', reverse('control:event.items.categories.add', kwargs={
|
||||
'event': self.event.slug,
|
||||
'organizer': self.event.organizer.slug,
|
||||
}), _("Create a new category"))
|
||||
self.fields['addon_category'].widget = Select2(
|
||||
attrs={
|
||||
'data-model-select2': 'generic',
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{% extends "error.html" %}
|
||||
{% load i18n %}
|
||||
{% load eventurl %}
|
||||
{% load urlreplace %}
|
||||
{% load static %}
|
||||
|
||||
{% block content %}
|
||||
<h1>{% trans "Please wait..." %}</h1>
|
||||
{{ notify_info|json_script:"notify_info" }}
|
||||
<script type="text/javascript" src="{% static "pretixcontrol/js/notify_parent.js" %}"></script>
|
||||
{% endblock %}
|
||||
@@ -22,9 +22,12 @@
|
||||
import collections.abc
|
||||
import warnings
|
||||
|
||||
from django.contrib import messages
|
||||
from django.core.paginator import (
|
||||
EmptyPage, PageNotAnInteger, UnorderedObjectListWarning,
|
||||
)
|
||||
from django.http.response import HttpResponseRedirect
|
||||
from django.shortcuts import render
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.views.generic import edit
|
||||
|
||||
@@ -38,7 +41,21 @@ class EventBasedFormMixin:
|
||||
return kwargs
|
||||
|
||||
|
||||
class CreateView(EventBasedFormMixin, edit.CreateView):
|
||||
class TellParentFormMixin:
|
||||
|
||||
def form_valid(self, form):
|
||||
result = super().form_valid(form)
|
||||
if self.request.GET.get('notify_parent') and isinstance(result, HttpResponseRedirect):
|
||||
message_store = messages.get_messages(self.request)
|
||||
msgs = [{'level': msg.level_tag, 'message': msg.message} for msg in message_store]
|
||||
return render(self.request, 'pretixcontrol/notify_parent.html', {
|
||||
'notify_info': {'object': self.object.pk, 'object_str': str(self.object), 'redirect_url': result.url, 'messages': msgs},
|
||||
})
|
||||
else:
|
||||
return result
|
||||
|
||||
|
||||
class CreateView(EventBasedFormMixin, TellParentFormMixin, edit.CreateView):
|
||||
"""
|
||||
Like Django's default CreateView, but passes the optional event
|
||||
argument to the form. This is necessary for I18nModelForms to work
|
||||
@@ -47,7 +64,7 @@ class CreateView(EventBasedFormMixin, edit.CreateView):
|
||||
pass
|
||||
|
||||
|
||||
class UpdateView(EventBasedFormMixin, edit.UpdateView):
|
||||
class UpdateView(EventBasedFormMixin, TellParentFormMixin, edit.UpdateView):
|
||||
"""
|
||||
Like Django's default UpdateView, but passes the optional event
|
||||
argument to the form. This is necessary for I18nModelForms to work
|
||||
|
||||
@@ -87,6 +87,8 @@ dialog::backdrop {
|
||||
100% { transform: skewX(0deg); }
|
||||
}
|
||||
|
||||
.modal-card.no-padding, .modal-card.no-padding .modal-card-content { padding: 0; }
|
||||
.modal-card.no-scroll { overflow: hidden; }
|
||||
|
||||
|
||||
/* Legacy dialogs (still used for #ajaxerr and #popupmodal) */
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
try {
|
||||
window.parent.postMessage({
|
||||
type: 'pretix:notify-parent',
|
||||
data: JSON.parse(document.getElementById('notify_info').textContent),
|
||||
}, location.origin)
|
||||
} catch (e) {
|
||||
console.error('Could not post message to parent.', e)
|
||||
}
|
||||
@@ -556,8 +556,6 @@ var editor = {
|
||||
editor.$fcv.get(0).height = editor.pdf_viewport.height
|
||||
editor.fabric = new fabric.Canvas('fabric-canvas')
|
||||
|
||||
editor.fabric.on('object:modified', editor._create_savepoint)
|
||||
editor.fabric.on('object:added', editor._create_savepoint)
|
||||
editor.fabric.on('selection:cleared', editor._update_toolbox)
|
||||
editor.fabric.on('selection:created', editor._update_toolbox)
|
||||
editor.fabric.on('selection:updated', editor._update_toolbox)
|
||||
@@ -590,6 +588,12 @@ var editor = {
|
||||
if (editor._window_loaded) {
|
||||
editor._ready()
|
||||
}
|
||||
|
||||
editor.fabric.on('object:modified', editor._create_savepoint)
|
||||
editor.fabric.on('object:added', editor._create_savepoint)
|
||||
editor.fabric.on('object:added', function(e) {
|
||||
editor.fabric.setActiveObject(e.target);
|
||||
})
|
||||
},
|
||||
|
||||
_window_load_event: function () {
|
||||
@@ -956,7 +960,6 @@ var editor = {
|
||||
mtr: true
|
||||
})
|
||||
editor.fabric.add(text)
|
||||
editor._create_savepoint()
|
||||
return text
|
||||
},
|
||||
|
||||
@@ -972,7 +975,6 @@ var editor = {
|
||||
rect.scaleToHeight(126)
|
||||
rect.setControlsVisibility({ mtr: false, mb: false, mt: false, mr: false, ml: false })
|
||||
editor.fabric.add(rect)
|
||||
editor._create_savepoint()
|
||||
return rect
|
||||
},
|
||||
|
||||
@@ -1009,7 +1011,6 @@ var editor = {
|
||||
mtr: true
|
||||
})
|
||||
editor.fabric.add(rect)
|
||||
editor._create_savepoint()
|
||||
$('#version-notice').show()
|
||||
return rect
|
||||
},
|
||||
@@ -1026,7 +1027,6 @@ var editor = {
|
||||
})
|
||||
rect.setControlsVisibility({ mtr: false })
|
||||
editor.fabric.add(rect)
|
||||
editor._create_savepoint()
|
||||
return rect
|
||||
},
|
||||
|
||||
@@ -1044,7 +1044,6 @@ var editor = {
|
||||
})
|
||||
rect.setControlsVisibility({ mtr: false, mb: false, mt: false, mr: false, ml: false })
|
||||
editor.fabric.add(rect)
|
||||
editor._create_savepoint()
|
||||
return rect
|
||||
},
|
||||
|
||||
|
||||
@@ -72,6 +72,10 @@ $(document).ajaxError(function (event, jqXHR, settings, thrownError) {
|
||||
})
|
||||
|
||||
let form_handlers = function (el) {
|
||||
// Prevent running multiple times on the same elements
|
||||
if (el.is('[data-formset-form-handlers-created]')) return
|
||||
el.find('[data-formset-form]').attr('data-formset-form-handlers-created', 'true')
|
||||
|
||||
el.trigger('rescan.areYouSure')
|
||||
el.find('[data-formset]').formset(
|
||||
{
|
||||
@@ -442,6 +446,15 @@ let form_handlers = function (el) {
|
||||
})
|
||||
})
|
||||
|
||||
function addClearButton($input) {
|
||||
var $btn = $("<button class='clear-input-button'><span class='fa fa-times'></span></button>").insertAfter($input).on('click', function(e) {
|
||||
$input.val('').trigger('input').trigger('change'); e.preventDefault()
|
||||
}).toggle($input.val() !== '')
|
||||
$input.on('input', function() {
|
||||
$btn.toggle($input.val() !== '')
|
||||
})
|
||||
}
|
||||
|
||||
el.find('div.scrolling-choice:not(.no-search)').each(function () {
|
||||
if ($(this).find('input[type=text]').length > 0) {
|
||||
return
|
||||
@@ -449,6 +462,7 @@ let form_handlers = function (el) {
|
||||
let $menu = $('<div>').addClass('choice-options-menu')
|
||||
let $inp_search = $('<input>').addClass('form-control').attr('type', 'text').attr('placeholder', gettext('Search query'))
|
||||
$menu.append($inp_search)
|
||||
addClearButton($inp_search)
|
||||
$(this).prepend($menu)
|
||||
|
||||
$inp_search.on('keyup change', function (e) {
|
||||
@@ -477,6 +491,7 @@ let form_handlers = function (el) {
|
||||
$menu.append($lbl_tgl)
|
||||
}
|
||||
$(this).prepend($menu)
|
||||
addClearButton($inp_search)
|
||||
|
||||
$(this).find('.choice-options-none').click(function (e) {
|
||||
$(this).closest('.scrolling-multiple-choice').find('input[type=checkbox]:not(.menu-checkbox)').prop('checked', false)
|
||||
@@ -736,6 +751,27 @@ let form_handlers = function (el) {
|
||||
questions_toggle_dependent()
|
||||
questions_init_photos(el)
|
||||
|
||||
el.find("[data-iframe-dialog]").on("click", function(e) {
|
||||
let url;
|
||||
if (this.tagName === "A" && !this.hasAttribute("data-iframe-dialog-url")) {
|
||||
url = this.getAttribute("href")
|
||||
url += (url.includes('?') ? '&' : '?') + 'notify_parent=true'
|
||||
} else {
|
||||
url = this.getAttribute("data-iframe-dialog-url")
|
||||
}
|
||||
show_iframe_dialog(url, (data) => {
|
||||
if (this.getAttribute("data-iframe-dialog-target")) {
|
||||
var $target = findDependency(this.getAttribute("data-iframe-dialog-target"), this)
|
||||
if ($target.is('select')) {
|
||||
$target.append(new Option(data.object_str, data.object, false, true)).trigger('change')
|
||||
}
|
||||
}
|
||||
})
|
||||
e.preventDefault()
|
||||
})
|
||||
}
|
||||
|
||||
function setup_placeholders() {
|
||||
let lastFocusedInput
|
||||
$(document).on('focusin', 'input, textarea', function (e) {
|
||||
lastFocusedInput = e.target
|
||||
@@ -1079,6 +1115,7 @@ $(function () {
|
||||
|
||||
setup_basics($('body'))
|
||||
form_handlers($('body'))
|
||||
setup_placeholders()
|
||||
$(document).trigger('pretix:bind-forms')
|
||||
|
||||
$('#ajaxerr').on('click', '.ajaxerr-close', ajaxErrDialog.hide)
|
||||
@@ -1121,3 +1158,66 @@ $(function () {
|
||||
return $(this).find('button:not([type=button]), input[type=submit]').length > 0
|
||||
}).areYouSure({ message: gettext('You have unsaved changes!') })
|
||||
})
|
||||
function show_iframe_dialog(url, callback) {
|
||||
function messageEvent(e) {
|
||||
if (e.origin === location.origin && e.data.type === 'pretix:dialog-loaded') {
|
||||
$dlg.find("iframe").attr("height", Math.min(window.innerHeight - 120, e.data.contentHeight|0)).css("visibility", "visible")
|
||||
$dlg.find("center").remove()
|
||||
}
|
||||
if (e.origin === location.origin && e.data.type === 'pretix:notify-parent') {
|
||||
$dlg[0].close()
|
||||
if (!callback(e.data.data)) {
|
||||
if (e.data.data.messages?.length) {
|
||||
alert(e.data.data.messages.map(m => m.message).join('\n\n'))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var $dlg = $('<dialog class="modal-card no-padding no-scroll" closedby="any"><center><i class="fa fa-cog big-rotating-icon"></i></center><iframe height="100" width="100%"></iframe></div>')
|
||||
.css('max-width', '60em')
|
||||
$dlg.find("iframe").attr("src", url).css("visibility", "hidden").css("border", "0")
|
||||
window.addEventListener('message', messageEvent)
|
||||
$dlg.appendTo("body")
|
||||
$dlg.on('close', function() {
|
||||
window.removeEventListener('message', messageEvent)
|
||||
$dlg.remove()
|
||||
})
|
||||
$dlg[0].showModal()
|
||||
}
|
||||
function setup_dialog_frame_events() {
|
||||
var dom_ready = false, parent_responded = false
|
||||
function notify_dialog_loaded() {
|
||||
console.log('ready', window.innerWidth, window.innerHeight, $('#page-wrapper > .container-fluid').outerHeight() + 20)
|
||||
window.parent.postMessage({
|
||||
type: 'pretix:dialog-loaded',
|
||||
contentHeight: $('#page-wrapper > .container-fluid').outerHeight() + 20,
|
||||
title: document.title,
|
||||
}, location.origin)
|
||||
}
|
||||
window.addEventListener('message', function(e) {
|
||||
if (e.source === window) return // don't handle messages from ourselves
|
||||
if (e.origin !== location.origin) return // only handle messages from same origin
|
||||
|
||||
if (e.data.type === 'pretix:dialog-handshake') {
|
||||
// we are inside an iframe in a dialog
|
||||
if (!parent_responded) {
|
||||
window.document.documentElement.classList.add('in-iframe')
|
||||
if (dom_ready) setTimeout(notify_dialog_loaded, 1)
|
||||
parent_responded = true
|
||||
}
|
||||
} else if (e.data.type === 'pretix:dialog-loading') {
|
||||
// we are parent to a dialog
|
||||
e.source.postMessage({ type: 'pretix:dialog-handshake' })
|
||||
}
|
||||
})
|
||||
$(function () {
|
||||
if (parent_responded) setTimeout(notify_dialog_loaded, 1)
|
||||
dom_ready = true
|
||||
})
|
||||
try {
|
||||
window.parent.postMessage({
|
||||
type: 'pretix:dialog-loading',
|
||||
}, location.origin)
|
||||
} catch {}
|
||||
}
|
||||
setup_dialog_frame_events()
|
||||
|
||||
@@ -417,6 +417,8 @@ div.scrolling-multiple-choice, div.scrolling-choice {
|
||||
}
|
||||
}
|
||||
}
|
||||
.clear-input-button { width: 2em; margin-left: -3em; margin-right: 1em; height: 2em; background: transparent; border: 0; color: #aaa; }
|
||||
.clear-input-button:hover { color: #777; }
|
||||
.team-permission-groups {
|
||||
border: 1px solid $input-border;
|
||||
border-radius: $input-border-radius;
|
||||
|
||||
@@ -898,6 +898,10 @@ tbody th {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
html.in-iframe body { background: white }
|
||||
.in-iframe #wrapper > nav.navbar, .in-iframe #page-wrapper > div > footer { display: none; }
|
||||
.in-iframe #page-wrapper { padding: 0 15px; min-height: 568px; border-left: 0; margin: 0; }
|
||||
|
||||
@import "../../pretixbase/scss/_rtl.scss";
|
||||
@import "../../bootstrap/scss/_rtl.scss";
|
||||
@import "_rtl.scss";
|
||||
|
||||
Reference in New Issue
Block a user