mirror of
https://github.com/bunkerity/bunkerweb
synced 2026-05-24 09:28:37 +00:00
handle advanced update + enhancements
* after mount, advanced mode is working with a copy and updatable template JSON that is reset on switch *remove cache with KeepAlive because this didn't fix the issue that inputs aren't in DOM for submit and instead listen to inputs in order to update the JSON files, JSON files will be use to submit data *add aria-hidden on select to avoid conflict with custom one for accessibility *update some inputs in order to work with the advanced mode listening inputs event * update datepicker to fit others props name allowing a default date
This commit is contained in:
parent
fafd7007f3
commit
05ad7373a7
8 changed files with 95 additions and 32 deletions
File diff suppressed because one or more lines are too long
|
|
@ -1,5 +1,5 @@
|
|||
<script setup>
|
||||
import { defineProps, reactive, onMounted, computed, KeepAlive } from "vue";
|
||||
import { defineProps, reactive, onMounted, computed, onUnmounted } from "vue";
|
||||
import Container from "@components/Widget/Container.vue";
|
||||
import Fields from "@components/Form/Fields.vue";
|
||||
import Title from "@components/Widget/Title.vue";
|
||||
|
|
@ -70,6 +70,7 @@ const data = reactive({
|
|||
keyword: "",
|
||||
type: "all",
|
||||
context: "all",
|
||||
base: JSON.parse(JSON.stringify(props.template)),
|
||||
filtered: computed(() => {
|
||||
const filterPlugin = [
|
||||
{
|
||||
|
|
@ -101,7 +102,7 @@ const data = reactive({
|
|||
];
|
||||
|
||||
// Deep copy
|
||||
const template = JSON.parse(JSON.stringify(props.template));
|
||||
const template = JSON.parse(JSON.stringify(data.base));
|
||||
// Start plugin filtering
|
||||
const filterPlugins = useFilter(template, filterPlugin);
|
||||
// Filter settings
|
||||
|
|
@ -226,19 +227,74 @@ const buttonSave = {
|
|||
disabled: false,
|
||||
color: "success",
|
||||
size: "normal",
|
||||
type: "submit",
|
||||
type: "bouton",
|
||||
attrs: {
|
||||
"data-submit-form": JSON.stringify(data.base),
|
||||
},
|
||||
containerClass: "flex justify-center",
|
||||
};
|
||||
|
||||
function updateInp(e) {
|
||||
// Check if target is child of data-advanced-form
|
||||
if (!e.target.closest("[data-advanced-form-plugin]")) return;
|
||||
|
||||
// Wait some ms that previous update logic is done like datepicker
|
||||
setTimeout(() => {
|
||||
let inpId, inpValue;
|
||||
|
||||
// Case target is input (a little different for datepicker)
|
||||
if (e.target.tagName === "INPUT") {
|
||||
inpId = e.target.id;
|
||||
inpValue = e.target.hasAttribute("data-timestamp")
|
||||
? e.target.getAttribute("data-timestamp")
|
||||
: e.target.value;
|
||||
}
|
||||
|
||||
// Case target is select
|
||||
if (
|
||||
e.target.closest("[data-field-container]") &&
|
||||
e.target.hasAttribute("data-setting-id") &&
|
||||
e.target.hasAttribute("data-setting-value")
|
||||
) {
|
||||
inpId = e.target.getAttribute("data-setting-id");
|
||||
inpValue = e.target.getAttribute("data-setting-value");
|
||||
}
|
||||
|
||||
// Case target is not an input-like
|
||||
if (!inpId) return;
|
||||
|
||||
data.base.find((plugin) => {
|
||||
const settings = plugin["settings"];
|
||||
// loop on each settings from plugin
|
||||
for (const [key, value] of Object.entries(settings)) {
|
||||
if (value.id === inpId) {
|
||||
value.value = inpValue;
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 50);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// Get first props.forms template name
|
||||
data.currPlugin = getFirstPlugin(props.template);
|
||||
data.plugins = getPluginNames(props.template);
|
||||
// Store update data on
|
||||
window.addEventListener("input", updateInp);
|
||||
window.addEventListener("change", updateInp);
|
||||
window.addEventListener("click", updateInp);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("input", updateInp);
|
||||
window.removeEventListener("change", updateInp);
|
||||
window.removeEventListener("click", updateInp);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Container
|
||||
data-advanced-form
|
||||
:tag="'form'"
|
||||
method="POST"
|
||||
:containerClass="`col-span-12 w-full m-1 p-1`"
|
||||
|
|
@ -258,24 +314,23 @@ onMounted(() => {
|
|||
<Select @inp="(v) => (data.context = v)" v-bind="selectContext" />
|
||||
</Container>
|
||||
<template v-for="plugin in data.filtered">
|
||||
<KeepAlive>
|
||||
<Container
|
||||
v-if="plugin.name === data.currPlugin"
|
||||
class="col-span-12 w-full"
|
||||
>
|
||||
<Title type="card" :title="plugin.name" />
|
||||
<Subtitle type="card" :subtitle="plugin.description" />
|
||||
<Container
|
||||
data-advanced-form-plugin
|
||||
v-if="plugin.name === data.currPlugin"
|
||||
class="col-span-12 w-full"
|
||||
>
|
||||
<Title type="card" :title="plugin.name" />
|
||||
<Subtitle type="card" :subtitle="plugin.description" />
|
||||
|
||||
<Container class="grid grid-cols-12 w-full relative">
|
||||
<template
|
||||
v-for="(setting, name, index) in plugin.settings"
|
||||
:key="index"
|
||||
>
|
||||
<Fields :setting="setting" />
|
||||
</template>
|
||||
</Container>
|
||||
<Container class="grid grid-cols-12 w-full relative">
|
||||
<template
|
||||
v-for="(setting, name, index) in plugin.settings"
|
||||
:key="index"
|
||||
>
|
||||
<Fields :setting="setting" />
|
||||
</template>
|
||||
</Container>
|
||||
</KeepAlive>
|
||||
</Container>
|
||||
</template>
|
||||
<Button v-bind="buttonSave" />
|
||||
</Container>
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ onMounted(() => {
|
|||
|
||||
<template>
|
||||
<Container
|
||||
data-easy-form
|
||||
:tag="'form'"
|
||||
method="POST"
|
||||
:containerClass="`col-span-12 w-full m-1 p-1`"
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@ const buttonSave = {
|
|||
|
||||
<template>
|
||||
<Container
|
||||
data-raw-form
|
||||
:tag="'form'"
|
||||
method="POST"
|
||||
:containerClass="`col-span-12 w-full m-1 p-1`"
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ const emits = defineEmits(["inp"]);
|
|||
:headerClass="props.headerClass"
|
||||
/>
|
||||
|
||||
<select :name="props.name" class="hidden">
|
||||
<select aria-hidden="true" :name="props.name" class="hidden">
|
||||
<option
|
||||
v-for="(value, id) in props.values"
|
||||
:key="id"
|
||||
|
|
@ -414,6 +414,8 @@ const emits = defineEmits(["inp"]);
|
|||
: '',
|
||||
'select-dropdown-btn',
|
||||
]"
|
||||
:data-setting-id="props.id"
|
||||
:data-setting-value="value"
|
||||
:aria-controls="`${props.id}-text`"
|
||||
:aria-checked="
|
||||
(select.value && select.value === value) ||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import "@assets/css/flatpickr.dark.css";
|
|||
columns : {"pc": 6, "tablet": 12, "mobile": 12},
|
||||
disabled: false,
|
||||
required: true,
|
||||
defaultDate: 1735682600000,
|
||||
value: 1735682600000,
|
||||
noPickBeforeStamp: 1735682600000,
|
||||
noPickAfterStamp: 1735689600000,
|
||||
inpClass: "text-center",
|
||||
|
|
@ -42,7 +42,7 @@ import "@assets/css/flatpickr.dark.css";
|
|||
@param {string} name - The name of the field. Case no label, this is the fallback. Can be a translation key or by default raw text.
|
||||
@param {array} popovers - List of popovers to display more information
|
||||
@param {string} [inpType="datepicker"] - The type of the field, useful when we have multiple fields in the same container to display the right field
|
||||
@param {string|number|date} [defaultDate=null] - Default date when instanciate
|
||||
@param {string|number|date} [value=""] - Default date when instanciate
|
||||
@param {string|number} [noPickBeforeStamp=""] - Impossible to pick a date before this date
|
||||
@param {string|number} [noPickAfterStamp=""] - Impossible to pick a date after this date
|
||||
@param {boolean} [hideLabel=false]
|
||||
|
|
@ -69,6 +69,11 @@ const props = defineProps({
|
|||
type: String,
|
||||
required: false,
|
||||
},
|
||||
value: {
|
||||
type: [String, Number, Date],
|
||||
required: false,
|
||||
default: "",
|
||||
},
|
||||
popovers: {
|
||||
type: Array,
|
||||
required: false,
|
||||
|
|
@ -98,7 +103,6 @@ const props = defineProps({
|
|||
required: false,
|
||||
default: "",
|
||||
},
|
||||
|
||||
columns: {
|
||||
type: [Object, Boolean],
|
||||
required: false,
|
||||
|
|
@ -112,11 +116,6 @@ const props = defineProps({
|
|||
type: Boolean,
|
||||
required: false,
|
||||
},
|
||||
defaultDate: {
|
||||
type: [String, Number, Date],
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
// Impossible to pick a date before this date
|
||||
noPickBeforeStamp: {
|
||||
type: [String, Number],
|
||||
|
|
@ -139,6 +138,7 @@ const props = defineProps({
|
|||
const date = reactive({
|
||||
isValid: true,
|
||||
format: "m/d/Y H:i:S",
|
||||
currStamp: "",
|
||||
});
|
||||
|
||||
const picker = reactive({
|
||||
|
|
@ -150,7 +150,7 @@ onMounted(() => {
|
|||
datepicker = flatpickr(`#${props.id}`, {
|
||||
locale: "en",
|
||||
dateFormat: date.format,
|
||||
defaultDate: props.defaultDate || "",
|
||||
defaultDate: props.value,
|
||||
enableTime: true,
|
||||
enableSeconds: true,
|
||||
time_24hr: true,
|
||||
|
|
@ -160,6 +160,7 @@ onMounted(() => {
|
|||
//Check if date is in interval
|
||||
try {
|
||||
const currStamp = Date.parse(dateStr);
|
||||
date.currStamp = currStamp;
|
||||
// Check pick is before min allow
|
||||
if (props.noPickBeforeStamp && currStamp < props.noPickBeforeStamp) {
|
||||
return instance.setDate(props.noPickBeforeStamp);
|
||||
|
|
@ -652,6 +653,7 @@ function setIndex(calendarEl, tabindex) {
|
|||
|
||||
<div class="relative flex flex-col items-start">
|
||||
<input
|
||||
:data-timestamp="date.currStamp"
|
||||
:tabindex="props.tabId"
|
||||
:aria-controls="props.id"
|
||||
:aria-selected="picker.isOpen ? 'true' : 'false'"
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ const emits = defineEmits(["inp"]);
|
|||
:headerClass="props.headerClass"
|
||||
/>
|
||||
|
||||
<select :name="props.name" class="hidden">
|
||||
<select aria-hidden="true" :name="props.name" class="hidden">
|
||||
<option
|
||||
v-for="(value, id) in props.values"
|
||||
:key="id"
|
||||
|
|
@ -341,6 +341,8 @@ const emits = defineEmits(["inp"]);
|
|||
: '',
|
||||
'select-dropdown-btn',
|
||||
]"
|
||||
:data-setting-id="props.id"
|
||||
:data-setting-value="value"
|
||||
:aria-controls="`${props.id}-text`"
|
||||
:aria-checked="
|
||||
(select.value && select.value === value) ||
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ const data = {
|
|||
type: "text",
|
||||
containerClass: "z-32",
|
||||
pattern: "^(\\/[\\-\\w.\\s]+)*\\/$",
|
||||
inpType: "input",
|
||||
inpType: "datepicker",
|
||||
name: "nginx prefix",
|
||||
columns: {
|
||||
pc: 4,
|
||||
|
|
|
|||
Loading…
Reference in a new issue