Adds TermCreationPanel component to the item submission flow. #573

This commit is contained in:
mateuswetah 2021-08-04 13:51:36 -03:00
parent 3e58ae0ce3
commit b50c407421
4 changed files with 319 additions and 13 deletions

View File

@ -7,7 +7,7 @@
:maxtags="maxtags"
v-model="valueComponent"
:allow-select-to-create="allowSelectToCreate"
:allow-new="allowNew"
:allow-new="allowNewFromOptions"
:taxonomy-id="taxonomyId"
:item-metadatum="itemMetadatum"
@showAddNewTerm="openTermCreationModal"
@ -17,7 +17,7 @@
:id="'tainacan-item-metadatum_id-' + itemMetadatum.metadatum.id + (itemMetadatum.parent_meta_id ? ('_parent_meta_id-' + itemMetadatum.parent_meta_id) : '')"
:is-modal="false"
:parent="0"
:allow-new="allowNew"
:allow-new="allowNewFromOptions"
@showAddNewTerm="openTermCreationModal"
:taxonomy_id="taxonomyId"
:selected="!valueComponent ? [] : valueComponent"
@ -32,7 +32,7 @@
/>
<div
v-if="displayCreateNewTerm"
v-if="displayCreateNewTerm && !isTermCreationPanelOpen"
class="add-new-term">
<a
@click="openTermCreationModal"
@ -45,6 +45,7 @@
</a>
</div>
<!-- Term creation modal, used on admin for a complete term creation -->
<b-modal
v-model="isTermCreationModalOpen"
trap-focus
@ -60,6 +61,17 @@
@onEditionCanceled="() => $console.log('Edition canceled')"
@onErrorFound="($event) => $console.log('Form with errors: ' + $event)" />
</b-modal>
<!-- Term creation panel, used on item submission block for a simpler term creation -->
<transition name="filter-item">
<term-creation-panel
v-if="isTermCreationPanelOpen"
:taxonomy-id="taxonomyId"
:edit-form="{ id: 'new', name: newTermName ? newTermName : '' }"
@onEditionFinished="($event) => addTermToBeCreated($event)"
@onEditionCanceled="() => isTermCreationPanelOpen = false"
@onErrorFound="($event) => $console.log('Form with errors: ' + $event)" />
</transition>
</div>
</template>
@ -79,9 +91,8 @@
disabled: false,
forcedComponentType: '',
maxtags: '',
allowNew: false,
allowSelectToCreate: false,
isTermCreationModalOpen: false,
newTermName: ''
},
data(){
return {
@ -89,8 +100,11 @@
taxonomyId: '',
taxonomy: '',
terms:[],
allowNew: false,
isAddingNewTermVaue: false
isAddingNewTermVaue: false,
isTermCreationModalOpen: false,
isTermCreationPanelOpen: false,
newTermName: '',
allowNewFromOptions: false
}
},
computed: {
@ -106,7 +120,10 @@
return '';
},
displayCreateNewTerm() {
return this.allowNew;
return this.allowNewFromOptions;
},
isOnItemSubmissionForm() {
return !this.itemMetadatum.item || !this.itemMetadatum.item.id;
}
},
watch: {
@ -120,8 +137,7 @@
this.taxonomyId = metadata_type_options.taxonomy_id;
this.taxonomy = metadata_type_options.taxonomy;
if (this.itemMetadatum.item && this.itemMetadatum.item.id && metadata_type_options && metadata_type_options.allow_new_terms && this.itemMetadatum.item)
this.allowNew = metadata_type_options.allow_new_terms == 'yes';
this.allowNewFromOptions = this.allowNew === false ? false : metadata_type_options.allow_new_terms == 'yes';
this.getTermsId();
},
@ -164,8 +180,16 @@
}
}
},
addTermToBeCreated(term) {
this.isTermCreationPanelOpen = false;
this.valueComponent = term.parent ? (term.parent + '>' + term.name) : term.name;
},
openTermCreationModal(newTerm) {
this.newTermName = newTerm.name;
if (this.isOnItemSubmissionForm)
this.isTermCreationPanelOpen = true;
else
this.isTermCreationModalOpen = true;
}
}

View File

@ -22,6 +22,7 @@ import ItemSubmission from '../../../item-submission/item-submission.vue';
// Remaining imports
import TainacanFormItem from '../../../admin/components/metadata-types/tainacan-form-item.vue';
import TermCreationPanel from '../../../item-submission/components/term-creation-panel.vue';
import HelpButton from '../../../admin/components/other/help-button.vue';
import store from '../../../admin/js/store/store';
import { I18NPlugin, UserPrefsPlugin, RouterHelperPlugin, ConsolePlugin, StatusHelperPlugin, CommentsStatusHelperPlugin } from '../../../admin/js/admin-utilities';
@ -81,6 +82,7 @@ export default (element) => {
/* Others */
Vue.component('tainacan-form-item', TainacanFormItem);
Vue.component('term-creation-panel', TermCreationPanel);
Vue.component('help-button', HelpButton);
const VueItemSubmission = new Vue({

View File

@ -0,0 +1,280 @@
<template>
<form
autofocus
role="dialog"
tabindex="-1"
aria-modal
id="termEditForm"
class="tainacan-form term-creation-panel"
@submit.prevent="saveEdition(editForm)">
<h4>{{ editForm & editForm.id && editForm.id != 'new' ? $i18n.get("title_term_edition") : $i18n.get("title_term_creation") }}</h4>
<div>
<b-loading
:is-full-page="false"
:active.sync="isLoading" />
<!-- Name -------------- -->
<b-field
:addons="false"
:type="((formErrors.name !== '' || formErrors.repeated !== '') && (formErrors.name !== undefined || formErrors.repeated !== undefined )) ? 'is-danger' : ''"
:message="formErrors.name ? formErrors.name : formErrors.repeated">
<label class="label is-inline">
{{ $i18n.get('label_name') }}
<span class="required-term-asterisk">*</span>
<help-button
:title="$i18n.get('label_name')"
:message="$i18n.get('info_help_term_name')"/>
</label>
<b-input
:placeholder="$i18n.get('label_term_without_name')"
v-model="editForm.name"
name="name"
@focus="clearErrors({ name: 'name', repeated: 'repeated' })"/>
</b-field>
<!-- Parent -------------- -->
<b-field
:addons="false"
:type="((formErrors.parent !== '' || formErrors.repeated !== '') && (formErrors.parent !== undefined || formErrors.repeated !== undefined )) ? 'is-danger' : ''"
:message="formErrors.parent ? formErrors : formErrors.repeated">
<label class="label is-inline">
{{ $i18n.get('label_parent_term') }}
<b-switch
@input="onToggleSwitch()"
id="tainacan-checkbox-has-parent"
size="is-small"
v-model="hasParent" />
<help-button
:title="$i18n.get('label_parent_term')"
:message="$i18n.get('info_help_parent_term')"/>
</label>
<b-autocomplete
id="tainacan-add-parent-field"
:placeholder="$i18n.get('instruction_parent_term')"
:data="parentTerms"
field="name"
clearable
v-model="parentTermName"
@select="onSelectParentTerm($event)"
:loading="isFetchingParentTerms"
@input="fetchParentTerms"
@focus="clearErrors('parent');"
:disabled="!hasParent"
check-infinite-scroll
@infinite-scroll="fetchMoreParentTerms">
<template slot-scope="props">
<div class="media">
<div
v-if="props.option.header_image"
class="media-left">
<img
width="28"
:src="props.option.header_image">
</div>
<div class="media-content">
{{ props.option.name }}
</div>
</div>
</template>
<template slot="empty">{{ $i18n.get('info_no_parent_term_found') }}</template>
</b-autocomplete>
</b-field>
<!-- Submit buttons -------------- -->
<div class="field is-grouped form-submit">
<div class="control">
<button
type="button"
class="button is-outlined"
@click.prevent="cancelEdition()"
slot="trigger">
{{ $i18n.get('cancel') }}
</button>
</div>
<div class="control">
<button
class="button is-success"
type="submit">
{{ $i18n.get('label_create_and_select') }}
</button>
</div>
</div>
</div>
</form>
</template>
<script>
import { formHooks } from "../../admin/js/mixins";
import { mapActions, mapGetters } from 'vuex';
export default {
name: 'TermEditionForm',
mixins: [ formHooks ],
props: {
editForm: Object,
taxonomyId: ''
},
data() {
return {
formErrors: {},
isFetchingParentTerms: false,
parentTerms: [],
parentTermName: '',
hasParent: false,
hasChangedParent: false,
initialParentId: undefined,
entityName: 'term',
isLoading: false,
parentTermSearchQuery: '',
parentTermSearchOffset: 0
}
},
mounted() {
this.hasParent = this.editForm.parent != undefined && this.editForm.parent > 0;
this.initialParentId = this.editForm.parent;
if (this.hasParent) {
this.isFetchingParentTerms = true;
this.fetchParentName({ taxonomyId: this.taxonomyId, parentId: this.editForm.parent })
.then((parentName) => {
this.parentTermName = parentName;
this.isFetchingParentTerms = false;
this.showCheckboxesWarning = false;
})
.catch((error) => {
this.$console.error(error);
this.isFetchingParentTerms = false;
this.showCheckboxesWarning = false;
});
}
},
methods: {
...mapActions('taxonomy', [
'sendChildTerm',
'updateChildTerm',
'fetchParentName',
'fetchPossibleParentTerms'
]),
...mapGetters('taxonomy', [
'getTerms'
]),
saveEdition(term) {
if (term.id === 'new') {
this.$emit('onEditionFinished', { name: this.editForm.name, parent: this.editForm.parent });
this.editForm = {};
this.formErrors = {};
this.isLoading = false;
}
},
cancelEdition() {
this.$emit('onEditionCanceled', this.editForm);
},
clearErrors(attributes) {
if(attributes instanceof Object){
for(let attribute in attributes){
this.formErrors[attribute] = undefined;
}
} else {
this.formErrors[attributes] = undefined;
}
},
fetchParentTerms: _.debounce(function(search) {
// String update
if (search != this.parentTermSearchQuery) {
this.parentTermSearchQuery = search;
this.parentTerms = [];
this.parentTermSearchOffset = 0;
}
// String cleared
if (!search.length) {
this.parentTermSearchQuery = search;
this.parentTerms = [];
this.parentTermSearchOffset = 0;
}
// No need to load more
if (this.parentTermSearchOffset > 0 && this.parentTerms.length >= this.totalTerms)
return
this.isFetchingParentTerms = true;
this.fetchPossibleParentTerms({
taxonomyId: this.taxonomyId,
termId: this.editForm.id,
search: this.parentTermSearchQuery,
offset: this.parentTermSearchOffset })
.then((res) => {
for (let term of res.parentTerms)
this.parentTerms.push(term);
this.parentTermSearchOffset += 12;
this.totalTerms = res.totalTerms;
this.isFetchingParentTerms = false;
})
.catch((error) => {
this.$console.error(error);
this.isFetchingParentTerms = false;
});
}, 500),
fetchMoreParentTerms: _.debounce(function () {
this.fetchParentTerms(this.parentTermSearchQuery)
}, 250),
onToggleSwitch() {
if (this.editForm.parent == 0) {
this.hasChangedParent = this.hasParent;
} else {
this.hasChangedParent = !this.hasParent;
}
this.showCheckboxesWarning = true;
this.clearErrors('parent');
},
onSelectParentTerm(selectedParentTerm) {
this.hasChangedParent = this.initialParentId != selectedParentTerm.id;
this.editForm.parent = selectedParentTerm.id;
this.selectedParentTerm = selectedParentTerm;
this.parentTermName = selectedParentTerm.name;
this.showCheckboxesWarning = true;
}
}
}
</script>
<style lang="scss" scoped>
.term-creation-panel {
padding-top: 6px;
h4 {
font-size: 0.875em;
}
&>div {
padding: 0 16px 16px;
border-left: 1px solid var(--tainacan-input-border-color, #dbdbdb);
border-bottom: 1px solid var(--tainacan-input-border-color, #dbdbdb);
column-count: 2;
@media screen and (max-width: 1024px) {
column-count: 1;
}
.field {
break-inside: avoid;
}
.form-submit {
padding-top: 0;
padding-bottom: 0;
column-span: all;
}
}
}
</style>