mirror of
https://github.com/pretix/pretix.git
synced 2026-11-10 01:17:07 +00:00
File settings handling; nicer file upload button
This commit is contained in:
1 parent
0f1f492397
commit
f018d32804
9 files changed
+52
-69
No files matched your search
+15
-31
@@ -1,14 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, useId, watchEffect } from "vue";
|
||||
import { computed, ref, useId, watchEffect } from "vue";
|
||||
|
||||
const gettext = (window as any).gettext;
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
const emit = defineEmits<{change: [File]}>()
|
||||
const selectedFile = defineModel<{"name": string; "url": string;}>()
|
||||
|
||||
const props = defineProps<{
|
||||
label?: I18nString;
|
||||
label?: LocalizableString;
|
||||
errors?: string[];
|
||||
help_text?: string;
|
||||
filename?: string;
|
||||
@@ -17,28 +15,16 @@ const props = defineProps<{
|
||||
}>();
|
||||
const id = useId();
|
||||
|
||||
const selectedFile = ref(null);
|
||||
function onChange(e) {
|
||||
selectedFile.value = (e.target as HTMLInputElement).files[0] || null
|
||||
emit("change", selectedFile.value)
|
||||
}
|
||||
|
||||
// Reset input field if a url is provided
|
||||
const inputRef = ref<HTMLInputElement>();
|
||||
watchEffect(() => {
|
||||
if (props.current_url && inputRef.value?.value) {
|
||||
inputRef.value.value = '';
|
||||
}
|
||||
})
|
||||
|
||||
const clearFile = () => {
|
||||
if (!inputRef.value) {
|
||||
return
|
||||
}
|
||||
var event = new Event('change');
|
||||
inputRef.value.value = '';
|
||||
inputRef.value.dispatchEvent(event)
|
||||
function clearFile() {
|
||||
selectedFile.value = null;
|
||||
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template lang="pug">
|
||||
@@ -48,16 +34,14 @@ const clearFile = () => {
|
||||
span.optional(v-if="!$attrs.required") {{ gettext("Optional") }}
|
||||
|
||||
div.col-md-9
|
||||
template(v-if="!!current_url")
|
||||
div(v-if="!!selectedFile")
|
||||
| {{ gettext("Currently") + ': ' }}
|
||||
a(:href="current_url" data-lightbox="input") {{ filename }}
|
||||
| {{ " " }}
|
||||
button.btn.btn-sm(@click.prevent="() => emit('change', null)") {{ gettext("Clear") }}
|
||||
br
|
||||
| {{ gettext("Change") + ': ' }}
|
||||
input(:id="id" @change="onChange" v-bind="$attrs" :required="$attrs.required && !current_url" type="file" style="display: inline" ref="inputRef")
|
||||
| {{ " " }}
|
||||
button.btn.btn-sm(v-if="selectedFile" @click.prevent="clearFile") {{ gettext("Clear") }}
|
||||
a(:href="selectedFile.url" data-lightbox="input") {{ selectedFile.name }}
|
||||
|
||||
.btn-group
|
||||
button.btn.btn-default(type="button" @click="inputRef.click()") Select file
|
||||
button.btn.btn-default(v-if="!!selectedFile || !!current_url" type="button" @click="clearFile") {{ gettext("Clear") }}
|
||||
input(:id="id" @change="onChange" v-bind="$attrs" :required="$attrs.required && !current_url" type="file" style="display: none" ref="inputRef")
|
||||
.help-block(v-if="!!help_text || !!props.default")
|
||||
template(v-if="!!help_text") {{ help_text }}
|
||||
br(v-if="!!help_text && !!props.default")
|
||||
|
||||
+5
-4
@@ -102,12 +102,12 @@ const placeholders = computed(() => {
|
||||
.panel-body(v-if="fieldConfig")
|
||||
span.text-muted(v-if="fieldgroup.description") {{ fieldgroup.description }}
|
||||
h4 {{ gettext("Content") }}
|
||||
.form-group()
|
||||
.form-group
|
||||
table.table.table-hover
|
||||
thead
|
||||
tr
|
||||
th.col-md-5(v-if="fieldgroup.display == 'with_label'") {{ gettext('Label') }}
|
||||
th(:class="'col-md-' + (fieldgroup.display == 'with_label' ? '6' : '11')") {{ gettext('Content') }}
|
||||
th.col-5(v-if="fieldgroup.display == 'with_label'") {{ gettext('Label') }}
|
||||
th(:class="'col-' + (fieldgroup.display == 'with_label' ? '6' : '11')") {{ gettext('Content') }}
|
||||
th.col-xs-1
|
||||
tbody
|
||||
tr(v-for="n, i in fieldConfig.entries.length" :key="i")
|
||||
@@ -123,9 +123,10 @@ const placeholders = computed(() => {
|
||||
:choices="Object.entries(store.variables.image).map(([k, v]) => [k, i18nstringLocalize(v.label)])"
|
||||
)
|
||||
td.text-right
|
||||
button.btn.btn-danger.form-control-static(type="button" @click="fieldConfig.entries.splice(n - 1, 1)")
|
||||
button.btn.btn-danger.form-control-static(type="button" @click="fieldConfig.entries.splice(n - 1, 1)" v-if="fieldConfig.entries.length > (fieldgroup.min_entries||0)")
|
||||
i.fa.fa-trash
|
||||
span.sr-only {{ gettext('Delete') }}
|
||||
.text-left.text-muted(v-else) {{ gettext("At least one field in this group is required") }}
|
||||
|
||||
button.btn.btn-default(type="button" @click="addVariable")
|
||||
i.fa.fa-plus
|
||||
|
||||
+6
-13
@@ -12,24 +12,17 @@ const layoutStyle = computed(() => {
|
||||
return Object.fromEntries(
|
||||
Object.entries(layout.style)
|
||||
.map(([k, v]) => {
|
||||
if (v.setting) {
|
||||
if (typeof v !== "string" && v.setting) {
|
||||
const settingDef = store.styles[store.layout.style].settings.find(
|
||||
(x) => x.identifier == v.setting,
|
||||
);
|
||||
const val = store.settings[v.setting];
|
||||
if (!settingDef) {
|
||||
v = null;
|
||||
} else if (
|
||||
settingDef.type == "image" &&
|
||||
val &&
|
||||
"file" in val &&
|
||||
val.file
|
||||
) {
|
||||
v = `url(${URL.createObjectURL(val.file)})`; // TODO: encode
|
||||
} else if (settingDef.type == "image" && val && val.url) {
|
||||
v = `url(${val.url})`;
|
||||
} else if (settingDef.type == "image" && val) {
|
||||
v = `url(${val.url})`; // TODO: encode
|
||||
} else if (settingDef.type == "image" && settingDef.default) {
|
||||
v = `url(${settingDef.default})`;
|
||||
v = `url(${settingDef.default})`; // TODO: encode
|
||||
} else {
|
||||
v = val;
|
||||
}
|
||||
@@ -53,8 +46,8 @@ const layoutStyle = computed(() => {
|
||||
|
||||
<style lang="css" scoped>
|
||||
.pass-container {
|
||||
width: 100%;
|
||||
max-width: 360px;
|
||||
width: 100%;
|
||||
max-width: 360px;
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
|
||||
|
||||
-3
@@ -19,9 +19,6 @@ const settingValue = computed(() => {
|
||||
const val = store.settings[config.setting];
|
||||
|
||||
if (settingDef.value.type == "image") {
|
||||
if (val && "file" in val && val.file) {
|
||||
return URL.createObjectURL(val.file);
|
||||
}
|
||||
if (val && "url" in val && val.url) {
|
||||
return val.url;
|
||||
} else if (settingDef.value.type == "image" && settingDef.value.default) {
|
||||
|
||||
@@ -18,6 +18,6 @@ const store = inject(StoreKey)!;
|
||||
:label="field.label" :type="field.type" :help_text="field.help_text"
|
||||
:min="field.min" :max="field.max" :defaultVal="field.default")
|
||||
FileInput(v-if='field.type == "image"' :label="field.label" :required="field.required"
|
||||
:help_text="field.help_text" @change="(v) => store.setSetting(field.identifier, v)"
|
||||
:filename="store.settings[field.identifier]?.name" :current_url="store.settings[field.identifier]?.url" :default="field.default")
|
||||
:help_text="field.help_text" @update:modelValue="(v) => store.setSetting(field.identifier, v)"
|
||||
:modelValue="store.settings[field.identifier]" :default="field.default")
|
||||
</template>
|
||||
@@ -51,6 +51,7 @@ type PlaceholderFieldGroupDefinition = BaseFieldGroupDefinition & {
|
||||
|
||||
type PredefinedFieldGroupDefinition = BaseFieldGroupDefinition & {
|
||||
type: "predefined";
|
||||
default_active: boolean;
|
||||
};
|
||||
|
||||
type LocalizableString = null | string | Record<string, string>;
|
||||
@@ -97,7 +98,7 @@ type LayoutData = {
|
||||
settings?: Record<string, any>;
|
||||
};
|
||||
|
||||
type PreviewLayout = {"style": Record<string, string | {settting: string}>, "rows": PreviewRow};
|
||||
type PreviewLayout = {"style": Record<string, string | {setting: string}>, "rows": PreviewRow};
|
||||
|
||||
type PreviewRow =
|
||||
| {
|
||||
|
||||
@@ -9,7 +9,7 @@ function getDefaultFieldgroupState(
|
||||
fieldgroup: FieldGroupDefinition,
|
||||
): FieldGroupConfig {
|
||||
if (fieldgroup.type == "predefined") {
|
||||
return { active: fieldgroup.required };
|
||||
return { active: fieldgroup.required || fieldgroup.default_active };
|
||||
} else if (fieldgroup.type == "placeholder") {
|
||||
return {
|
||||
overflow: null,
|
||||
@@ -84,8 +84,14 @@ export function createWalletStore(config: {
|
||||
settings[setting.identifier] =
|
||||
this.layout.settings[setting.identifier];
|
||||
} else if (setting.type == "image") {
|
||||
settings[setting.identifier] =
|
||||
this.layout.file_settings[setting.identifier];
|
||||
const val = this.layout.file_settings[setting.identifier];
|
||||
if (val && "file" in val && val.file) {
|
||||
settings[setting.identifier] = {"name": val.file.name, "url": URL.createObjectURL(val.file)};
|
||||
} else if (val && "url" in val && val.url) {
|
||||
settings[setting.identifier] = val;
|
||||
} else {
|
||||
settings[setting.identifier] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return settings;
|
||||
|
||||
@@ -121,6 +121,14 @@ class CustomFieldEntry(FieldEntry[MaybeTranslatedString]):
|
||||
|
||||
class PredefinedFieldGroup(FieldGroup):
|
||||
type = FieldGroupType.PREDEFINED
|
||||
default_active: bool
|
||||
|
||||
def __init__(self, identifier: str, name: str, description=None, required=False, default_active=True):
|
||||
self.identifier = identifier
|
||||
self.name = name
|
||||
self.required = required
|
||||
self.description = description or ""
|
||||
self.default_active = default_active
|
||||
|
||||
def layout_schema(
|
||||
self,
|
||||
@@ -129,6 +137,11 @@ class PredefinedFieldGroup(FieldGroup):
|
||||
):
|
||||
return {"type": "object", "properties": {"active": {"type": "boolean"}}}
|
||||
|
||||
def asdict(self, locales: list[str], context: LayoutContext):
|
||||
return {
|
||||
**super().asdict(locales, context),
|
||||
"default_active": self.default_active,
|
||||
}
|
||||
|
||||
class PlaceholderFieldGroup(FieldGroup):
|
||||
type = FieldGroupType.PLACEHOLDER
|
||||
|
||||
@@ -29,7 +29,6 @@ from pretix.plugins.wallet.styles.base import (
|
||||
ColorSettingsField,
|
||||
FieldGroupDisplay,
|
||||
FloatSettingsField,
|
||||
ImageFieldGroup,
|
||||
ImageSettingsField,
|
||||
PassStyle,
|
||||
PlaceholderFieldEntry,
|
||||
@@ -232,17 +231,6 @@ class GoogleWalletDefaultEventTicket(GoogleWalletEventTicketStyle):
|
||||
@property
|
||||
def fieldgroups(self):
|
||||
return [
|
||||
ImageFieldGroup(
|
||||
identifier="logo",
|
||||
name=_("Logo"),
|
||||
min_entries=0,
|
||||
max_entries=1,
|
||||
default_entries=[
|
||||
PlaceholderFieldEntry(
|
||||
content="poweredby",
|
||||
)
|
||||
],
|
||||
),
|
||||
PredefinedFieldGroup(identifier="venue", name=_("Venue")),
|
||||
PredefinedFieldGroup(identifier="date", name=_("Date")),
|
||||
PredefinedFieldGroup(identifier="seating", name=_("Seating")),
|
||||
|
||||
Reference in new issue
Block a user