adds field modal

This commit is contained in:
buttle 2024-01-26 18:42:06 +01:00
parent 92477db091
commit 9cbf6352a3
5 changed files with 321 additions and 53 deletions

View file

@ -6,39 +6,55 @@ This file is part of LiberaForms.
-->
<template>
<!-- v-if="getRenderItemsAsTable() == true" -->
<ItemsGrid v-if="display_items" />
<FieldEditor />
<FieldModal v-if="!is_loading"
:show_modal="show_field_modal"
:data="field_modal_data"
@closeFieldModal="closeFieldModal" />
</template>
<script>
import { computed, provide } from "vue";
import { computed, provide, ref, toRefs, reactive } from "vue";
import { dataDisplayStore } from '@/store.js'
import ItemsGrid from '@/components/itemsRenderer/ItemsGrid.vue'
import FieldEditor from '@/components/itemsRenderer/FieldEditor.vue'
import FieldModal from '@/components/itemsRenderer/FieldModal.vue'
export default {
name: 'ItemsRenderer',
components: {
ItemsGrid, FieldEditor
ItemsGrid, FieldModal
},
setup() {
const store = dataDisplayStore()
function showFieldModal(item_id, field_name, field_value) {
console.log("showFieldModal")
//this.field_name = field_name
//this.field_value = field_value
//this.item_id = item_id
//if (this.edit_mode == true) {
// this.create_form_data()
//}
//this.toggleModal()
const show_field_modal = ref(false)
const field_modal_data = reactive({
field_name: "",
field_value: "",
field_label: "",
item_id: null
})
function showFieldEditor(data) {
//console.log("showFieldEditor:", data.item_id, data.field_name, data.field_value)
if (data !== undefined) {
field_modal_data.item_id = data.item_id
field_modal_data.field_name = data.field_name
field_modal_data.field_value = data.field_value
field_modal_data.field_label = store.getFieldLabel(data.field_name)
}
show_field_modal.value = true
}
provide('showFieldEditor', showFieldEditor)
function closeFieldModal(data) {
show_field_modal.value = false
}
provide('showFieldModal', showFieldModal)
return {
display_items: computed(() => {
@ -53,7 +69,8 @@ export default {
}
return false
}),
store
field_modal_data, show_field_modal, closeFieldModal,
is_loading: computed(() => store.downloading_items),
}
},
}

View file

@ -1,35 +0,0 @@
<!--
This file is part of LiberaForms.
# SPDX-FileCopyrightText: 2024 LiberaForms.org
# SPDX-License-Identifier: AGPL-3.0-or-later
-->
<template>
</template>
<script>
import { computed } from "vue";
import { dataDisplayStore } from '@/store.js'
export default {
name: 'FieldEditor',
components: {
},
setup() {
const store = dataDisplayStore()
return {
}
},
}
</script>
<style scoped>
</style>

View file

@ -0,0 +1,275 @@
<!--
This file is part of LiberaForms.
# SPDX-FileCopyrightText: 2024 LiberaForms.org
# SPDX-License-Identifier: AGPL-3.0-or-later
-->
<!--:class="{show, 'd-block': active}"-->
<template>
<div v-if="show_modal">
<div class="modal fade show d-block"
@keydown.esc="closeModal()"
tabindex="-1"
role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
{{ t(data.field_label) }}
</h5>
<button type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
v-on:click="closeModal()">
<XIcon aria-hidden="true" />
</button>
</div>
<div class="modal-body">
<template v-if="edit_mode">
<div class="form-group">
<input v-if="field_type == 'text' ||
field_type == 'date' ||
field_type == 'number'"
:type="field_type"
class="form-control"
v-model="data.field_value" />
<select v-else-if="field_type == 'select'"
v-model="data.field_value"
class="form-control form-select">
<option v-for="option in field_options"
:value="option.value">
{{ option.label }}
</option>
</select>
<template v-else-if="field_type == 'checkbox-group'"
v-for="option in field_options">
<div class="form-check">
<input type="checkbox"
class="form-check-input"
:id="option.value"
:value="option.value"
v-model="multi_choice" />
<label :for="option.value" class="form-check-label">
{{ option.label }}
</label>
</div>
</template>
<template v-else-if="field_type == 'radio-group'"
v-for="option in field_options">
<div class="form-check">
<input type="radio"
class="form-check-input"
name="RadioGroup"
:id="option.value"
:value="option.value"
v-model="data.field_value" />
<label :for="option.value" class="form-check-label">
{{ option.label }}
</label>
</div>
</template>
<textarea v-else-if="field_type == 'textarea'"
class="form-control"
rows="6"
v-model="data.field_value">
</textarea>
</div>
</template>
<div v-else-if="data.field_name.startsWith('checkbox')"
v-html="formatted_field_value()">
</div>
<div v-else>
<span v-if="!data.field_value" class="ds-empty-field">{{ t("Empty") }}</span>
<span v-else>{{ formatted_field_value() }}</span>
</div>
</div>
<div class="modal-footer">
<button v-if="!edit_mode && (
field_type == 'text' ||
field_type == 'date' ||
field_type == 'number' ||
field_type == 'textarea')"
type="button"
class="btn btn-outline-primary">
<!--
v-clipboard:copy="field_value"
v-clipboard:success="onCopied">
-->
{{ t("Copy") }}
</button>
<button v-if="can_edit && !edit_mode"
type="button"
class="btn btn-outline-primary"
data-dismiss="modal"
v-on:click="edit_mode = true">
{{ t("Edit") }}
</button>
<button v-if="edit_mode"
type="button"
class="btn btn-primary"
v-on:click="saveField()">
{{ t("Save") }}
</button>
<button type="button"
class="btn btn-secondary"
v-on:click="closeModal()">
{{ close_button_text }}
</button>
</div>
</div>
</div>
</div>
<div class="modal-backdrop fade show"></div>
</div>
</template>
<script>
import axios from 'axios';
import { computed, ref, watch } from "vue";
import { dataDisplayStore } from '@/store.js'
import { XIcon } from '@zhuowenli/vue-feather-icons'
export default {
name: 'FieldModal',
components: {
XIcon
},
props: {
data: Object,
show_modal: Boolean,
},
emits: ['closeFieldModal'],
setup(props, { emit }) {
const store = dataDisplayStore()
const edit_mode = ref(false)
const field_options = ref([])
const multi_choice = ref([])
const field_type = ref(null)
const can_edit = store.can_edit
var field_structure = {}
watch(() => JSON.stringify(props.data), (current_value) => {
let structure = store.getFieldStructure(props.data.field_name)
field_structure = structure !== undefined ? structure : {"type": null}
field_type.value = field_structure.type
createFormData()
})
function createFormData() {
//console.log("data.value", props.data.field_value)
field_options.value = []
multi_choice.value = []
if (field_type.value == 'select' ||
field_type.value == 'checkbox-group' ||
field_type.value == 'radio-group') {
if (props.data.field_value !== undefined) {
multi_choice.value = props.data.field_value.split(', ')
}
field_structure.values.forEach((value) => {
field_options.value.push({
value: value.value,
label: value.label
})
});
//console.log("field_options", field_options.value)
}
}
function formatted_field_value() {
if (!props.data.field_value) {
return props.data.field_value
}
if (props.data.field_name.startsWith('checkbox')) {
var values = props.data.field_value.split(', ')
var html = '<ul>'
values.forEach((value) => {
var label = store.getOptionLabel({'field_name': props.data.field_name,
'option_value': value})
html = html + '<li style="margin-left: -1.3em;">' + label + '</li>'
});
html = html + '</ul>'
return html
}
if (props.data.field_name.startsWith('radio-group') ||
props.data.field_name.startsWith('select')){
var label = store.getOptionLabel({'field_name': props.data.field_name,
'option_value': props.data.field_value})
if (label) {
return label
}
}
return props.data.field_value
}
function saveField() {
let item_id = props.data.item_id
var item = store.items.find(item => item.id === item_id)
if (item !== undefined) {
if (field_type.value == "checkbox-group") {
if (multi_choice.value.length > 0 && multi_choice.value[0].trim() === "") {
// multi_choice may contain "" in as the first item of the array. why?
multi_choice.value = multi_choice.value.slice(1)
}
var field_value = multi_choice.value.join(', ')
} else {
var field_value = props.data.field_value !== undefined ? props.data.field_value.trim() : ""
}
let field_name = props.data.field_name
var initial_value = item.data[field_name]
if (field_name.startsWith('checkbox') && field_value === "") {
// answer.data dict must not include this key with an empty value
// database expects dict without this key
delete item.data[field_name];
} else {
item.data[field_name] = field_value
}
var json = JSON.stringify({item_data: item.data});
axios.patch(store.item_endpoint+item_id+'/save', json, {
headers: { 'Content-Type': 'application/json' }
})
.then(response => {
if (response.data.saved == true) {
item.data = response.data.data
}
})
.catch(e => {
console.log(e)
item.data[field_name] = initial_value
});
}
closeModal()
}
function closeModal() {
edit_mode.value = false
field_structure = {}
emit('closeFieldModal')
}
const close_button_text = computed(() => {
return edit_mode.value ? "Cancel" : "Close"//this.t("Cancel") : this.t("Close")
})
function t(word) {
return word
}
return {
show_modal: computed(() => { return props.show_modal }),
can_edit, edit_mode, formatted_field_value,
field_type, field_options, multi_choice,
t,
close_button_text, closeModal,
saveField,
}
},
}
</script>
<style scoped>
</style>

View file

@ -37,7 +37,7 @@ export default {
setup(props) {
const store = dataDisplayStore()
const showFieldModal = inject('showFieldModal')
const showFieldEditor = inject('showFieldEditor')
const fieldValue = computed(() => {
if (props.field_name.endsWith('__html')) {
@ -78,7 +78,11 @@ export default {
return false
}
function showModal() {
showFieldModal(props.item_id, props.field_name, props.field_value)
showFieldEditor({
"item_id": props.item_id,
"field_name": props.field_name,
"field_value": props.field_value
})
}
return {

View file

@ -103,6 +103,13 @@ export const dataDisplayStore = defineStore("dataDisplayStore", {
}
return field_value
},
getFieldLabel: (state) => (field_name) => {
var field = state.user_prefs.field_index.find(x => x.name === field_name)
if (field !== undefined) {
return field.label
}
return null
},
getOptionLabel: (state) => (payload) => {
var field_name = payload.field_name
var option_value = payload.option_value