Add public filters based on meta data (#3673)

* Add public filters based on meta data

* Fix licenseheaders

* ignore empty values

* Fix tests

* Full non-widget implementation

* Widget support

* Add a few tests

* Allow to reorder properties

* Fix isort

* Allow to opt-out for specific events

* Fix name clash between new and old field to make migration feasible
This commit is contained in:
Raphael Michel
2023-11-10 12:10:01 +01:00
committed by GitHub
parent c0007a9566
commit d7aa94d6ae
34 changed files with 829 additions and 82 deletions

View File

@@ -1093,6 +1093,46 @@ Vue.component('pretix-widget-event-form', {
}
});
Vue.component('pretix-widget-event-list-filter-field', {
template: ('<div class="pretix-widget-event-list-filter-field">'
+ '<label :for="id">{{ field.label }}</label>'
+ '<select :id="id" :name="field.key" @change="onChange($event)" :value="currentValue">'
+ '<option v-for="choice in field.choices" :value="choice[0]">{{ choice[1] }}</option>'
+ '</select>'
+ '</div>'),
props: {
field: Object
},
methods: {
onChange: function(event) {
var filterParams = new URLSearchParams(this.$root.filter);
if (event.target.value) {
filterParams.set(this.field.key, event.target.value);
} else {
filterParams.delete(this.field.key);
}
this.$root.filter = filterParams.toString();
this.$root.loading++;
this.$root.reload();
},
},
computed: {
id: function () {
return widget_id + "_" + this.field.key;
},
currentValue: function () {
var filterParams = new URLSearchParams(this.$root.filter);
return filterParams.get(this.field.key) || "";
},
},
});
Vue.component('pretix-widget-event-list-filter-form', {
template: ('<div class="pretix-widget-event-list-filter-form">'
+ '<pretix-widget-event-list-filter-field v-for="field in $root.meta_filter_fields" :field="field" :key="field.key"></pretix-widget-event-list-filter-field>'
+ '</div>'),
});
Vue.component('pretix-widget-event-list-entry', {
template: ('<a :class="classObject" @click.prevent.stop="select">'
+ '<div class="pretix-widget-event-list-entry-name">{{ event.name }}</div>'
@@ -1142,6 +1182,7 @@ Vue.component('pretix-widget-event-list', {
+ '<strong>{{ $root.name }}</strong>'
+ '</div>'
+ '<div class="pretix-widget-event-description" v-if="$root.parent_stack.length > 0 && $root.frontpage_text" v-html="$root.frontpage_text"></div>'
+ '<pretix-widget-event-list-filter-form v-if="!$root.disable_filters && $root.meta_filter_fields.length > 0"></pretix-widget-event-list-filter-form>'
+ '<pretix-widget-event-list-entry v-for="event in $root.events" :event="event" :key="event.url"></pretix-widget-event-list-entry>'
+ '<p class="pretix-widget-event-list-load-more" v-if="$root.has_more_events"><button @click.prevent.stop="load_more">'+strings.load_more+'</button></p>'
+ '</div>'),
@@ -1360,6 +1401,9 @@ Vue.component('pretix-widget-event-calendar', {
+ '</div>'
+ '<div class="pretix-widget-event-description" v-if="$root.parent_stack.length > 0 && $root.frontpage_text" v-html="$root.frontpage_text"></div>'
// Filter
+ '<pretix-widget-event-list-filter-form v-if="!$root.disable_filters && $root.meta_filter_fields.length > 0"></pretix-widget-event-list-filter-form>'
// Calendar navigation
+ '<div class="pretix-widget-event-calendar-head">'
+ '<a class="pretix-widget-event-calendar-previous-month" href="#" @click.prevent.stop="prevmonth" role="button">&laquo; '
@@ -1442,6 +1486,9 @@ Vue.component('pretix-widget-event-week-calendar', {
+ '<strong>{{ $root.name }}</strong>'
+ '</div>'
// Filter
+ '<pretix-widget-event-list-filter-form v-if="!$root.disable_filters && $root.meta_filter_fields.length > 0"></pretix-widget-event-list-filter-form>'
// Calendar navigation
+ '<div class="pretix-widget-event-description" v-if="$root.parent_stack.length > 0 && $root.frontpage_text" v-html="$root.frontpage_text"></div>'
+ '<div class="pretix-widget-event-calendar-head">'
@@ -1671,6 +1718,7 @@ var shared_root_methods = {
root.view = "weeks";
root.name = data.name;
root.frontpage_text = data.frontpage_text;
root.meta_filter_fields = data.meta_filter_fields;
} else if (data.days !== undefined) {
root.days = data.days;
root.date = null;
@@ -1679,6 +1727,7 @@ var shared_root_methods = {
root.view = "days";
root.name = data.name;
root.frontpage_text = data.frontpage_text;
root.meta_filter_fields = data.meta_filter_fields;
} else if (data.events !== undefined) {
root.events = root.append_events && root.events ? root.events.concat(data.events) : data.events;
root.append_events = false;
@@ -1687,6 +1736,7 @@ var shared_root_methods = {
root.name = data.name;
root.frontpage_text = data.frontpage_text;
root.has_more_events = data.has_more_events;
root.meta_filter_fields = data.meta_filter_fields;
} else {
root.view = "event";
root.name = data.name;
@@ -1917,6 +1967,7 @@ var create_widget = function (element) {
var skip_ssl = element.attributes["skip-ssl-check"] ? true : false;
var disable_iframe = element.attributes["disable-iframe"] ? true : false;
var disable_vouchers = element.attributes["disable-vouchers"] ? true : false;
var disable_filters = element.attributes["disable-filters"] ? true : false;
var widget_data = JSON.parse(JSON.stringify(window.PretixWidget.widget_data));
var filter = element.attributes.filter ? element.attributes.filter.value : null;
var items = element.attributes.items ? element.attributes.items.value : null;
@@ -1990,12 +2041,14 @@ var create_widget = function (element) {
widget_id: 'pretix-widget-' + widget_id,
vouchers_exist: false,
disable_vouchers: disable_vouchers,
disable_filters: disable_filters,
cart_exists: false,
itemcount: 0,
overlay: null,
poweredby: "",
has_seating_plan: false,
has_seating_plan_waitinglist: false,
meta_filter_fields: [],
}
},
created: function () {

View File

@@ -139,6 +139,41 @@
}
}
.event-list-filter-form {
.event-list-filter-form-row {
display: flex;
flex-direction: row;
align-items: end;
.form-group {
display: block;
width: 100%;
margin: 0 15px 0 0;
}
button {
flex: 0;
white-space: nowrap;
/* Visual alignment with the selects */
padding-top: 7px;
padding-bottom: 7px;
}
}
margin-bottom: 15px;
}
@media (max-width: $screen-xs-max) {
.event-list-filter-form {
.event-list-filter-form-row {
display: flex;
flex-direction: column;
align-items: stretch;
.form-group {
display: block;
width: 100%;
margin: 0 0 5px;
}
}
}
}

View File

@@ -99,7 +99,7 @@
input:checked + .pretix-widget-icon-cart {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.534 3.097a.317.317 0 0 1-.067.197L3.56 4.42a.207.207 0 0 1-.16.084.207.207 0 0 1-.159-.084l-.907-1.126a.317.317 0 0 1-.067-.197c0-.154.103-.282.227-.282.06 0 .117.031.159.084l.521.642V2.252c0-.154.102-.281.226-.281.124 0 .227.127.227.281v1.289l.521-.642a.205.205 0 0 1 .159-.084c.124 0 .227.128.227.282ZM2.267 6.756c0-.312-.202-.563-.453-.563-.252 0-.454.251-.454.563 0 .312.202.563.454.563.251 0 .453-.251.453-.563Zm3.174 0c0-.312-.202-.563-.454-.563-.251 0-.453.251-.453.563 0 .312.202.563.453.563.252 0 .454-.251.454-.563Zm.453-4.785c0-.154-.103-.282-.227-.282H1.413c-.035-.211-.039-.563-.28-.563H.227c-.124 0-.227.128-.227.282 0 .153.103.281.227.281h.722l.627 3.62c-.049.127-.216.466-.216.603 0 .153.103.281.227.281h3.627c.124 0 .227-.128.227-.281 0-.154-.103-.282-.227-.282H1.955c.036-.088.085-.18.085-.281 0-.102-.032-.212-.046-.308l3.698-.537c.117-.018.202-.141.202-.281V1.971Z' transform='matrix(2.52069 0 0 2.02994 -.035 -.523)'/%3E%3C/svg%3E%0A");
}
input[type="text"], input[type="number"] {
input[type="text"], input[type="number"], select {
line-height: normal;
border: 1px solid $input-border;
border-radius: $input-border-radius;
@@ -640,6 +640,42 @@
}
}
.pretix-widget-event-list-filter-form {
display: flex;
flex-direction: row;
align-items: end;
margin-bottom: 15px;
.pretix-widget-event-list-filter-field {
display: block;
width: 100%;
margin: 0 15px 0 0;
label {
display: inline-block;
font-weight: bold;
margin-bottom: 5px;
}
select {
display: block;
width: 100%;
}
}
.pretix-widget-event-list-filter-field:last-child {
margin: 0;
}
}
.pretix-widget.pretix-widget-mobile .pretix-widget-event-list-filter-form {
display: block;
.pretix-widget-event-list-filter-field {
display: block;
margin: 0 0 5px;
}
}
@keyframes pretix-widget-bounce-in {
0% {
transform: scale(0);