eventcally/project/templates/layout_vue.html
2021-10-14 13:09:32 +02:00

363 lines
14 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "layout.html" %}
{% block header_before_site_js %}
<link
type="text/css"
rel="stylesheet"
href="https://unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.min.css"
/>
{% if False | env_override('FLASK_DEBUG') %}
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
{% else %}
<script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
{% endif %}
<script src="https://unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.min.js"></script>
<script src="https://unpkg.com/vue-router@2.0.0/dist/vue-router.min.js"></script>
<script src="https://unpkg.com/vue-i18n@8.25.0/dist/vue-i18n.min.js"></script>
<script src="https://unpkg.com/axios@0.21.1/dist/axios.min.js"></script>
<script src="https://unpkg.com/lodash@4.17.21/lodash.min.js"></script>
<script src="https://unpkg.com/portal-vue@2.1.7/dist/portal-vue.umd.min.js"></script>
<link
href="https://unpkg.com/vue-typeahead-bootstrap@2.12.0/dist/VueTypeaheadBootstrap.css"
rel="stylesheet"
/>
<script src="https://unpkg.com/vue-typeahead-bootstrap@2.12.0/dist/VueTypeaheadBootstrap.umd.min.js"></script>
<script src="https://unpkg.com/vee-validate@3.4.11/dist/vee-validate.full.min.js"></script>
<script src="{{ url_for('static', filename='vue/common/typeahead.vue.js')}}"></script>
<script src="{{ url_for('static', filename='vue/common/validated-input.vue.js')}}"></script>
<script src="{{ url_for('static', filename='vue/common/validated-switch.vue.js')}}"></script>
<script src="{{ url_for('static', filename='vue/common/validated-textarea.vue.js')}}"></script>
{% block component_scripts %}
{% endblock %}
{% endblock %}
{% block content %}
<div id="vue-container"><router-view></router-view></div>
<script>
Vue.component("vue-typeahead-bootstrap", VueTypeaheadBootstrap);
Vue.component("ValidationObserver", VeeValidate.ValidationObserver);
Vue.component("ValidationProvider", VeeValidate.ValidationProvider);
Vue.component("custom-typeahead", CustomTypeahead);
Vue.component("validated-input", ValidatedInput);
Vue.component("validated-switch", ValidatedSwitch);
Vue.component("validated-textarea", ValidatedTextarea);
{% block component_definitions %}
{% endblock %}
const sharedMessages = {
en: {
shared: {
models: {
adminUnitRelation: {
targetOrganization: "Other organization",
autoVerifyEventReferenceRequests: "Verify reference requests automatically",
autoVerifyEventReferenceRequestsDescription: "If set, all upcoming reference requests of the other organization are verified automatically.",
verify: "Verify other organization",
verifyDescription: "If set, events of the other organization are publicly visible.",
},
adminUnitInvitation: {
email: "Email",
emailDescription: "The invitation will be sent to this email address.",
organizationName: "New organization's name",
relationAutoVerifyEventReferenceRequests: "Verify reference requests automatically",
relationAutoVerifyEventReferenceRequestsDescription: "If set, all upcoming reference requests of the new organization are verified automatically.",
relationVerify: "Verify new organization",
relationVerifyDescription: "If set, events of the new organization are publicly visible.",
},
eventReport: {
contactName: "Name",
contactEmail: "Email",
contactNameDescription: "First and last name",
message: "Message",
messageDescription: "Briefly describe in your words why the event is objectionable.",
},
},
cancel: "Cancel",
decline: "Decline",
submit: "Submit",
edit: "Edit",
delete: "Delete",
emptyData: "No data available",
errors: {
uniqueViolation:
"An entry with the entered values already exists. Duplicate entries are not allowed.",
},
toast: {
errorTitle: "Error",
successTitle: "Success",
},
autocomplete: {
instruction: "Type to search",
},
validation: {
alpha: "The {_field_} field may only contain alphabetic characters",
alpha_num:
"The {_field_} field may only contain alpha-numeric characters",
alpha_dash:
"The {_field_} field may contain alpha-numeric characters as well as dashes and underscores",
alpha_spaces:
"The {_field_} field may only contain alphabetic characters as well as spaces",
between: "The {_field_} field must be between {min} and {max}",
confirmed: "The {_field_} field confirmation does not match",
digits:
"The {_field_} field must be numeric and exactly contain {length} digits",
dimensions:
"The {_field_} field must be {width} pixels by {height} pixels",
email: "The {_field_} field must be a valid email",
excluded: "The {_field_} field is not a valid value",
ext: "The {_field_} field is not a valid file",
image: "The {_field_} field must be an image",
integer: "The {_field_} field must be an integer",
length: "The {_field_} field must be {length} long",
max_value: "The {_field_} field must be {max} or less",
max: "The {_field_} field may not be greater than {length} characters",
mimes: "The {_field_} field must have a valid file type",
min_value: "The {_field_} field must be {min} or more",
min: "The {_field_} field must be at least {length} characters",
numeric: "The {_field_} field may only contain numeric characters",
oneOf: "The {_field_} field is not a valid value",
regex: "The {_field_} field format is invalid",
required_if: "The {_field_} field is required",
required: "The {_field_} field is required",
size: "The {_field_} field size must be less than {size}KB",
double: "The {_field_} field must be a valid decimal",
},
},
},
de: {
shared: {
models: {
adminUnitRelation: {
targetOrganization: "Andere Organisation",
autoVerifyEventReferenceRequests:
"Empfehlungsanfragen automatisch verifizieren",
autoVerifyEventReferenceRequestsDescription: "Wenn gesetzt, werden alle zukünftigen Empfehlungsanfragen der anderen Organisation automatisch verifiziert.",
verify: "Andere Organisation verifizieren",
verifyDescription: "Wenn gesetzt, sind Veranstaltungen der anderen Organisation öffentlich sichtbar.",
},
adminUnitInvitation: {
email: "Email",
emailDescription: "An diese Email-Adresse wird die Einladung gesendet.",
organizationName: "Name der neuen Organisation",
relationAutoVerifyEventReferenceRequests: "Empfehlungsanfragen automatisch verifizieren",
relationAutoVerifyEventReferenceRequestsDescription: "Wenn gesetzt, werden alle zukünftigen Empfehlungsanfragen der neuen Organisation automatisch verifiziert.",
relationVerify: "Neue Organisation verifizieren",
relationVerifyDescription: "Wenn gesetzt, sind Veranstaltungen der neuen Organisation öffentlich sichtbar.",
},
eventReport: {
contactName: "Name",
contactNameDescription: "Vor- und Nachname",
contactEmail: "Email-Adresse",
message: "Mitteilung",
messageDescription: "Beschreibe kurz in deinen Worten, warum die Veranstaltung zu beanstanden ist.",
},
},
cancel: "Abbrechen",
decline: "Ablehnen",
submit: "Senden",
edit: "Bearbeiten",
delete: "Löschen",
emptyData: "Keine Daten vorhanden",
errors: {
uniqueViolation:
"Ein Eintrag mit den eingegebenen Werten existiert bereits. Doppelte Einträge sind nicht erlaubt.",
},
toast: {
errorTitle: "Fehler",
successTitle: "Erfolg",
},
autocomplete: {
instruction: "Tippen um zu suchen",
},
validation: {
alpha: "{_field_} darf nur alphabetische Zeichen enthalten",
alpha_dash:
"{_field_} darf alphanumerische Zeichen sowie Striche und Unterstriche enthalten",
alpha_num: "{_field_} darf nur alphanumerische Zeichen enthalten",
alpha_spaces:
"{_field_} darf nur alphanumerische Zeichen und Leerzeichen enthalten",
between: "{_field_} muss zwischen {min} und {max} liegen",
confirmed: "Die Bestätigung von {_field_} stimmt nicht überein",
digits:
"{_field_} muss numerisch sein und exakt {length} Ziffern enthalten",
dimensions: "{_field_} muss {width} x {height} Bildpunkte groß sein",
email: "{_field_} muss eine gültige E-Mail-Adresse sein",
excluded: "{_field_} muss ein gültiger Wert sein",
ext: "{_field_} muss eine gültige Datei sein",
image: "{_field_} muss eine Grafik sein",
oneOf: "{_field_} muss ein gültiger Wert sein",
integer: "{_field_} muss eine ganze Zahl sein",
length: "Die Länge von {_field_} muss {length} sein",
max: "{_field_} darf nicht länger als {length} Zeichen sein",
max_value: "{_field_} darf maximal {max} sein",
mimes: "{_field_} muss einen gültigen Dateityp haben",
min: "{_field_} muss mindestens {length} Zeichen lang sein",
min_value: "{_field_} muss mindestens {min} sein",
numeric: "{_field_} darf nur numerische Zeichen enthalten",
regex: "Das Format von {_field_} ist ungültig",
required: "{_field_} ist ein Pflichtfeld",
required_if: "{_field_} ist ein Pflichtfeld",
size: "{_field_} muss kleiner als {size}KB sein",
double: "Das Feld {_field_} muss eine gültige Dezimalzahl sein",
},
},
},
};
const i18n = new VueI18n({
locale: "de",
messages: sharedMessages,
silentFallbackWarn: true,
});
VeeValidate.configure({
defaultMessage: (field, values) => {
return i18n.t(`shared.validation.${values._rule_}`, values);
}
});
Object.keys(VeeValidate.Rules).forEach((rule) => {
VeeValidate.extend(rule, VeeValidate.Rules[rule]);
});
{% block vue_routes %}
{% endblock %}
const router = new VueRouter({
routes: routes,
mode: "history",
base: "/",
});
axios.defaults.baseURL = "{{ get_base_url() }}";
axios.interceptors.request.use(
function (config) {
if (config) {
this.app.handleAxiosStart(config);
}
return config;
},
function (error) {
this.app.handleAxiosError(error);
return Promise.reject(error);
}
);
axios.interceptors.response.use(
function (response) {
if (response && response.config) {
this.app.handleAxiosFinish(response.config);
}
return response;
},
function (error) {
this.app.handleAxiosError(error);
return Promise.reject(error);
}
);
var app = new Vue({
el: "#vue-container",
i18n,
router: router,
data() {
return {};
},
methods: {
handleAxiosStart(config) {
if (
config &&
config.handler &&
config.handler.hasOwnProperty("handleRequestStart")
) {
config.handler.handleRequestStart();
}
if (
config &&
config.hasOwnProperty("handleLoading")
) {
config.handleLoading(true);
}
},
handleAxiosFinish(config) {
if (
config &&
config.handler &&
config.handler.hasOwnProperty("handleRequestFinish")
) {
config.handler.handleRequestFinish();
}
if (
config &&
config.hasOwnProperty("handleLoading")
) {
config.handleLoading(false);
}
},
handleAxiosError(error) {
if (error && error.config) {
this.handleAxiosFinish(error.config);
}
const status = error && error.response && error.response.status;
let message = error.message || error;
if (status == 400) {
message =
(error &&
error.response &&
error.response.data &&
error.response.data.message) ||
error;
errorName =
error &&
error.response &&
error.response.data &&
error.response.data.name;
if (errorName == "Unique Violation") {
message = this.$t("shared.errors.uniqueViolation");
}
}
if (
error.config &&
error.config.handler &&
error.config.handler.hasOwnProperty("handleRequestError")
) {
error.config.handler.handleRequestError(error, message);
} else {
this.makeErrorToast(message);
}
},
makeErrorToast(message) {
this.makeToast(message, "danger", this.$t("shared.toast.errorTitle"));
},
makeSuccessToast(message) {
this.makeToast(
message,
"success",
this.$t("shared.toast.successTitle")
);
},
makeToast(message, variant, title) {
this.$bvToast.toast(message, {
title: title,
variant: variant,
toaster: "b-toaster-top-center",
noCloseButton: true,
solid: true,
});
},
goBack(fallbackPath) {
window.history.length > 1 ? this.$router.go(-1) : this.$router.push({ path: fallbackPath })
},
},
});
</script>
{% endblock %}