adds field modal
This commit is contained in:
parent
92477db091
commit
9cbf6352a3
|
@ -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),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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>
|
275
src/components/itemsRenderer/FieldModal.vue
Normal file
275
src/components/itemsRenderer/FieldModal.vue
Normal 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>
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue