Rename category files to taxonomy
This commit is contained in:
parent
430b57c135
commit
77f253358d
|
@ -0,0 +1,370 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="page-container primary-page">
|
||||
<tainacan-title />
|
||||
<b-tabs v-model="activeTab">
|
||||
<b-tab-item :label="$i18n.get('taxonomy')">
|
||||
<form
|
||||
v-if="taxonomy != null && taxonomy != undefined"
|
||||
class="tainacan-form"
|
||||
label-width="120px">
|
||||
|
||||
<!-- Name -------------------------------- -->
|
||||
<b-field
|
||||
:addons="false"
|
||||
:label="$i18n.get('label_name')"
|
||||
:type="editFormErrors['name'] != undefined ? 'is-danger' : ''"
|
||||
:message="editFormErrors['name'] != undefined ? editFormErrors['name'] : ''">
|
||||
<help-button
|
||||
:title="$i18n.getHelperTitle('taxonomies', 'name')"
|
||||
:message="$i18n.getHelperMessage('taxonomies', 'name')"/>
|
||||
<b-input
|
||||
id="tainacan-text-name"
|
||||
v-model="form.name"
|
||||
@focus="clearErrors('name')"
|
||||
@blur="updateSlug()"/>
|
||||
</b-field>
|
||||
|
||||
<!-- Description -------------------------------- -->
|
||||
<b-field
|
||||
:addons="false"
|
||||
:label="$i18n.get('label_description')"
|
||||
:type="editFormErrors['description'] != undefined ? 'is-danger' : ''"
|
||||
:message="editFormErrors['description'] != undefined ? editFormErrors['description'] : ''">
|
||||
<help-button
|
||||
:title="$i18n.getHelperTitle('taxonomies', 'description')"
|
||||
:message="$i18n.getHelperMessage('taxonomies', 'description')"/>
|
||||
<b-input
|
||||
id="tainacan-text-description"
|
||||
type="textarea"
|
||||
v-model="form.description"
|
||||
@focus="clearErrors('description')"/>
|
||||
</b-field>
|
||||
|
||||
<!-- Status -------------------------------- -->
|
||||
<b-field
|
||||
:addons="false"
|
||||
:label="$i18n.get('label_status')"
|
||||
:type="editFormErrors['status'] != undefined ? 'is-danger' : ''"
|
||||
:message="editFormErrors['status'] != undefined ? editFormErrors['status'] : ''">
|
||||
<help-button
|
||||
:title="$i18n.getHelperTitle('taxonomies', 'status')"
|
||||
:message="$i18n.getHelperMessage('taxonomies', 'status')"/>
|
||||
<b-select
|
||||
id="tainacan-select-status"
|
||||
v-model="form.status"
|
||||
@focus="clearErrors('status')"
|
||||
:placeholder="$i18n.get('instruction_select_a_status')">
|
||||
<option
|
||||
v-for="statusOption in statusOptions"
|
||||
:key="statusOption.value"
|
||||
:value="statusOption.value"
|
||||
:disabled="statusOption.disabled">{{ statusOption.label }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
|
||||
<!-- Slug -------------------------------- -->
|
||||
<b-field
|
||||
:addons="false"
|
||||
:label="$i18n.get('label_slug')"
|
||||
:type="editFormErrors['slug'] != undefined ? 'is-danger' : ''"
|
||||
:message="editFormErrors['slug'] != undefined ? editFormErrors['slug'] : ''">
|
||||
<help-button
|
||||
:title="$i18n.getHelperTitle('taxonomies', 'slug')"
|
||||
:message="$i18n.getHelperMessage('taxonomies', 'slug')"/>
|
||||
<b-icon :class="{'is-loading': isUpdatingSlug}"/>
|
||||
<b-input
|
||||
@input="updateSlug()"
|
||||
id="tainacan-text-slug"
|
||||
v-model="form.slug"
|
||||
@focus="clearErrors('slug')"
|
||||
:disabled="isUpdatingSlug"/>
|
||||
</b-field>
|
||||
|
||||
<!-- Allow Insert -->
|
||||
<b-field
|
||||
:addons="false"
|
||||
:label="$i18n.get('label_taxonomy_allow_new_terms')">
|
||||
<help-button
|
||||
:title="$i18n.getHelperTitle('taxonomies', 'allow_insert')"
|
||||
:message="$i18n.getHelperMessage('taxonomies', 'allow_insert')"/>
|
||||
<div class="block" >
|
||||
<b-checkbox
|
||||
v-model="form.allowInsert"
|
||||
true-value="yes"
|
||||
false-value="no">
|
||||
{{ labelNewTerms() }}
|
||||
</b-checkbox>
|
||||
</div>
|
||||
</b-field>
|
||||
|
||||
<!-- Submit -->
|
||||
<div class="field is-grouped form-submit">
|
||||
<div class="control">
|
||||
<button
|
||||
id="button-cancel-taxonomy-creation"
|
||||
class="button is-outlined"
|
||||
type="button"
|
||||
@click="cancelBack">{{ $i18n.get('cancel') }}</button>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button
|
||||
id="button-submit-taxonomy-creation"
|
||||
@click.prevent="onSubmit"
|
||||
class="button is-success">{{ $i18n.get('save') }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="help is-danger">{{ formErrorMessage }}</p>
|
||||
</form>
|
||||
</b-tab-item>
|
||||
|
||||
<b-tab-item :label="$i18n.get('terms')">
|
||||
<!-- Terms List -->
|
||||
<terms-list :taxonomy-id="taxonomyId"/>
|
||||
</b-tab-item>
|
||||
|
||||
<b-loading
|
||||
:active.sync="isLoadingTaxonomy"
|
||||
:can-cancel="false"/>
|
||||
</b-tabs>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { wpAjax } from "../../js/mixins";
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import TermsList from '../lists/terms-list.vue'
|
||||
import htmlToJSON from 'html-to-json';
|
||||
import CustomDialog from '../other/custom-dialog.vue';
|
||||
|
||||
export default {
|
||||
name: 'TaxonomyEditionForm',
|
||||
mixins: [ wpAjax ],
|
||||
data(){
|
||||
return {
|
||||
taxonomyId: String,
|
||||
activeTab: 0,
|
||||
taxonomy: null,
|
||||
isLoadingTaxonomy: false,
|
||||
isUpdatingSlug: false,
|
||||
form: {
|
||||
name: String,
|
||||
status: String,
|
||||
description: String,
|
||||
slug: String,
|
||||
allowInsert: String
|
||||
},
|
||||
statusOptions: [{
|
||||
value: 'publish',
|
||||
label: this.$i18n.get('publish')
|
||||
}, {
|
||||
value: 'draft',
|
||||
label: this.$i18n.get('draft')
|
||||
}, {
|
||||
value: 'private',
|
||||
label: this.$i18n.get('private')
|
||||
}, {
|
||||
value: 'trash',
|
||||
label: this.$i18n.get('trash')
|
||||
}],
|
||||
editFormErrors: {},
|
||||
formErrorMessage: '',
|
||||
// baseUrl: tainacan_plugin.base_url,
|
||||
}
|
||||
},
|
||||
components: {
|
||||
TermsList
|
||||
},
|
||||
beforeRouteLeave( to, from, next ) {
|
||||
let formNotSaved = false;
|
||||
|
||||
if (this.taxonomy.name != this.form.name)
|
||||
formNotSaved = true;
|
||||
if (this.taxonomy.description != this.form.description)
|
||||
formNotSaved = true;
|
||||
if (this.taxonomy.slug != this.form.slug)
|
||||
formNotSaved = true;
|
||||
if (this.taxonomy.allow_insert != this.form.allowInsert)
|
||||
formNotSaved = true;
|
||||
if (this.taxonomy.status != this.form.status)
|
||||
formNotSaved = true;
|
||||
|
||||
if (formNotSaved) {
|
||||
this.$modal.open({
|
||||
parent: this,
|
||||
component: CustomDialog,
|
||||
props: {
|
||||
icon: 'alert',
|
||||
title: this.$i18n.get('label_warning'),
|
||||
message: this.$i18n.get('info_warning_taxonomy_not_saved'),
|
||||
onConfirm: () => {
|
||||
next();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('taxonomy', [
|
||||
'createTaxonomy',
|
||||
'updateTaxonomy',
|
||||
'fetchTaxonomy',
|
||||
'fetchOnlySlug'
|
||||
]),
|
||||
...mapGetters('taxonomy',[
|
||||
'getTaxonomy',
|
||||
]),
|
||||
onSubmit() {
|
||||
|
||||
this.isLoadingTaxonomy = true;
|
||||
|
||||
let data = {
|
||||
taxonomyId: this.taxonomyId,
|
||||
name: this.form.name,
|
||||
description: this.form.description,
|
||||
slug: this.form.slug,
|
||||
status: this.form.status,
|
||||
allowInsert: this.form.allowInsert
|
||||
};
|
||||
|
||||
this.updateTaxonomy(data)
|
||||
.then(updatedTaxonomy => {
|
||||
|
||||
this.taxonomy = updatedTaxonomy;
|
||||
|
||||
// Fill this.form data with current data.
|
||||
this.form.name = this.taxonomy.name;
|
||||
this.form.slug = this.taxonomy.slug;
|
||||
this.form.description = this.taxonomy.description;
|
||||
this.form.status = this.taxonomy.status;
|
||||
this.form.allowInsert = this.taxonomy.allow_insert;
|
||||
|
||||
this.isLoadingTaxonomy = false;
|
||||
this.formErrorMessage = '';
|
||||
this.editFormErrors = {};
|
||||
|
||||
this.$router.push(this.$routerHelper.getCategoriesPath());
|
||||
})
|
||||
.catch((errors) => {
|
||||
for (let error of errors.errors) {
|
||||
for (let attribute of Object.keys(error)) {
|
||||
this.editFormErrors[attribute] = error[attribute];
|
||||
}
|
||||
}
|
||||
this.formErrorMessage = errors.error_message;
|
||||
|
||||
this.isLoadingTaxonomy = false;
|
||||
});
|
||||
},
|
||||
updateSlug(){
|
||||
if(!this.form.name || this.form.name.length <= 0){
|
||||
return;
|
||||
}
|
||||
|
||||
this.isUpdatingSlug = true;
|
||||
|
||||
this.getSamplePermalink(this.taxonomyId, this.form.name, this.form.slug)
|
||||
.then(samplePermalink => {
|
||||
|
||||
let promise = htmlToJSON.parse(samplePermalink, {
|
||||
permalink($doc) {
|
||||
return $doc.find('#editable-post-name-full').text();
|
||||
}
|
||||
});
|
||||
|
||||
promise.done((result) => {
|
||||
this.form.slug = result.permalink;
|
||||
//this.$console.info(this.form.slug);
|
||||
});
|
||||
|
||||
this.isUpdatingSlug = false;
|
||||
this.formErrorMessage = '';
|
||||
this.editFormErrors = {};
|
||||
})
|
||||
.catch(errors => {
|
||||
this.$console.error(errors);
|
||||
|
||||
this.isUpdatingSlug = false;
|
||||
});
|
||||
|
||||
},
|
||||
createNewTaxonomy() {
|
||||
// Puts loading on Draft Taxonomy creation
|
||||
this.isLoadingTaxonomy = true;
|
||||
|
||||
// Creates draft Taxonomy
|
||||
let data = {
|
||||
name: '',
|
||||
description: '',
|
||||
status: 'auto-draft',
|
||||
slug: '',
|
||||
allowInsert: '',
|
||||
};
|
||||
|
||||
this.createTaxonomy(data)
|
||||
.then(res => {
|
||||
|
||||
this.taxonomyId = res.id;
|
||||
this.taxonomy = res;
|
||||
|
||||
// Fill this.form data with current data.
|
||||
this.form.name = this.taxonomy.name;
|
||||
this.form.description = this.taxonomy.description;
|
||||
this.form.slug = this.taxonomy.slug;
|
||||
this.form.allowInsert = this.taxonomy.allow_insert;
|
||||
|
||||
// Pre-fill status with publish to incentivate it
|
||||
this.form.status = 'publish';
|
||||
|
||||
this.isLoadingTaxonomy = false;
|
||||
|
||||
})
|
||||
.catch(error => this.$console.error(error));
|
||||
},
|
||||
clearErrors(attribute) {
|
||||
this.editFormErrors[attribute] = undefined;
|
||||
},
|
||||
cancelBack(){
|
||||
this.$router.push(this.$routerHelper.getCategoriesPath());
|
||||
},
|
||||
labelNewTerms(){
|
||||
return ( this.form.allowInsert === 'yes' ) ? this.$i18n.get('label_yes') : this.$i18n.get('label_no');
|
||||
}
|
||||
},
|
||||
created(){
|
||||
|
||||
if (this.$route.fullPath.split("/").pop() === "new") {
|
||||
this.createNewTaxonomy();
|
||||
} else if (this.$route.fullPath.split("/").pop() === "edit" || this.$route.fullPath.split("/").pop() === "terms") {
|
||||
|
||||
this.isLoadingTaxonomy = true;
|
||||
|
||||
// Obtains current taxonomy ID from URL
|
||||
this.pathArray = this.$route.fullPath.split("/").reverse();
|
||||
this.taxonomyId = this.pathArray[1];
|
||||
|
||||
this.fetchTaxonomy(this.taxonomyId).then(res => {
|
||||
this.taxonomy = res.taxonomy;
|
||||
|
||||
// Fill this.form data with current data.
|
||||
this.form.name = this.taxonomy.name;
|
||||
this.form.description = this.taxonomy.description;
|
||||
this.form.slug = this.taxonomy.slug;
|
||||
this.form.status = this.taxonomy.status;
|
||||
this.form.allowInsert = this.taxonomy.allow_insert;
|
||||
|
||||
this.isLoadingTaxonomy = false;
|
||||
});
|
||||
|
||||
if (this.$route.fullPath.split("/").pop() === "terms")
|
||||
this.activeTab = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
@ -0,0 +1,287 @@
|
|||
<template>
|
||||
<div
|
||||
v-if="totalCategories > 0 && !isLoading"
|
||||
class="table-container">
|
||||
|
||||
<div class="selection-control">
|
||||
<div class="field select-all is-pulled-left">
|
||||
<span>
|
||||
<b-checkbox
|
||||
@click.native="selectAllCategoriesOnPage()"
|
||||
:value="allCategoriesOnPageSelected">{{ $i18n.get('label_select_all_taxonomies_page') }}</b-checkbox>
|
||||
</span>
|
||||
</div>
|
||||
<div class="field is-pulled-right">
|
||||
<b-dropdown
|
||||
position="is-bottom-left"
|
||||
v-if="taxonomies[0].current_user_can_edit"
|
||||
:disabled="!isSelectingCategories"
|
||||
id="bulk-actions-dropdown">
|
||||
<button
|
||||
class="button is-white"
|
||||
slot="trigger">
|
||||
<span>{{ $i18n.get('label_bulk_actions') }}</span>
|
||||
<b-icon icon="menu-down"/>
|
||||
</button>
|
||||
|
||||
<b-dropdown-item
|
||||
id="item-delete-selected-items"
|
||||
@click="deleteSelectedCategories()">
|
||||
{{ $i18n.get('label_delete_selected_taxonomies') }}
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item disabled>{{ $i18n.get('label_edit_selected_taxonomies') + ' (Not ready)' }}
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper">
|
||||
<table class="tainacan-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<!-- Checking list -->
|
||||
<th>
|
||||
|
||||
<!-- nothing to show on header -->
|
||||
</th>
|
||||
<!-- Name -->
|
||||
<th>
|
||||
<div class="th-wrap">{{ $i18n.get('label_name') }}</div>
|
||||
</th>
|
||||
<!-- Description -->
|
||||
<th>
|
||||
<div class="th-wrap">{{ $i18n.get('label_description') }}</div>
|
||||
</th>
|
||||
<!-- Actions -->
|
||||
<th class="actions-header">
|
||||
|
||||
<!-- nothing to show on header for actions cell-->
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
:class="{ 'selected-row': selectedCategories[index] }"
|
||||
:key="index"
|
||||
v-for="(taxonomy, index) of taxonomies">
|
||||
<!-- Checking list -->
|
||||
<td
|
||||
:class="{ 'is-selecting': isSelectingCategories }"
|
||||
class="checkbox-cell">
|
||||
<b-checkbox
|
||||
size="is-small"
|
||||
v-model="selectedCategories[index]"/>
|
||||
</td>
|
||||
<!-- Name -->
|
||||
<td
|
||||
class="column-default-width column-main-content"
|
||||
@click="goToTaxonomyEditPage(taxonomy.id)"
|
||||
:label="$i18n.get('label_name')"
|
||||
:aria-label="$i18n.get('label_name') + ': ' + taxonomy.name">
|
||||
<p
|
||||
v-tooltip="{
|
||||
content: taxonomy.name,
|
||||
autoHide: false,
|
||||
placement: 'auto-start'
|
||||
}">
|
||||
{{ taxonomy.name }}</p>
|
||||
</td>
|
||||
<!-- Description -->
|
||||
<td
|
||||
class="column-large-width"
|
||||
@click="goToTaxonomyEditPage(taxonomy.id)"
|
||||
:label="$i18n.get('label_description')"
|
||||
:aria-label="$i18n.get('label_description') + ': ' + taxonomy.description">
|
||||
<p
|
||||
v-tooltip="{
|
||||
content: taxonomy.description,
|
||||
autoHide: false,
|
||||
placement: 'auto-start'
|
||||
}">
|
||||
{{ taxonomy.description }}</p>
|
||||
</td>
|
||||
<!-- Actions -->
|
||||
<td
|
||||
@click="goToTaxonomyEditPage(taxonomy.id)"
|
||||
class="actions-cell column-default-width"
|
||||
:label="$i18n.get('label_actions')">
|
||||
<div class="actions-container">
|
||||
<a
|
||||
id="button-edit"
|
||||
:aria-label="$i18n.getFrom('taxonomies','edit_item')"
|
||||
@click="goToTaxonomyEditPage(taxonomy.id)">
|
||||
<b-icon
|
||||
type="is-secondary"
|
||||
icon="pencil"/>
|
||||
</a>
|
||||
<a
|
||||
id="button-delete"
|
||||
:aria-label="$i18n.get('label_button_delete')"
|
||||
@click.prevent.stop="deleteOneTaxonomy(taxonomy.id)">
|
||||
<b-icon
|
||||
type="is-secondary"
|
||||
icon="delete"/>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
import CustomDialog from '../other/custom-dialog.vue';
|
||||
|
||||
export default {
|
||||
name: 'CategoriesList',
|
||||
data() {
|
||||
return {
|
||||
selectedCategories: [],
|
||||
allCategoriesOnPageSelected: false,
|
||||
isSelectingCategories: false
|
||||
}
|
||||
},
|
||||
props: {
|
||||
isLoading: false,
|
||||
totalCategories: 0,
|
||||
page: 1,
|
||||
taxonomiesPerPage: 12,
|
||||
taxonomies: Array
|
||||
},
|
||||
watch: {
|
||||
taxonomies() {
|
||||
this.selectedCategories = [];
|
||||
for (let i = 0; i < this.taxonomies.length; i++)
|
||||
this.selectedCategories.push(false);
|
||||
},
|
||||
selectedCategories() {
|
||||
let allSelected = true;
|
||||
let isSelecting = false;
|
||||
for (let i = 0; i < this.selectedCategories.length; i++) {
|
||||
if (this.selectedCategories[i] == false) {
|
||||
allSelected = false;
|
||||
} else {
|
||||
isSelecting = true;
|
||||
}
|
||||
}
|
||||
this.allCategoriesOnPageSelected = allSelected;
|
||||
this.isSelectingCategories = isSelecting;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('taxonomy', [
|
||||
'deleteTaxonomy'
|
||||
]),
|
||||
selectAllCategoriesOnPage() {
|
||||
for (let i = 0; i < this.selectedCategories.length; i++)
|
||||
this.selectedCategories.splice(i, 1, !this.allCategoriesOnPageSelected);
|
||||
},
|
||||
deleteOneTaxonomy(taxonomyId) {
|
||||
this.$modal.open({
|
||||
parent: this,
|
||||
component: CustomDialog,
|
||||
props: {
|
||||
icon: 'alert',
|
||||
title: this.$i18n.get('label_warning'),
|
||||
message: this.$i18n.get('info_warning_taxonomy_delete'),
|
||||
onConfirm: () => {
|
||||
this.deleteTaxonomy(taxonomyId)
|
||||
.then(() => {
|
||||
// this.$toast.open({
|
||||
// duration: 3000,
|
||||
// message: this.$i18n.get('info_taxonomy_deleted'),
|
||||
// position: 'is-bottom',
|
||||
// type: 'is-secondary',
|
||||
// queue: true
|
||||
// });
|
||||
for (let i = 0; i < this.selectedCategories.length; i++) {
|
||||
if (this.selectedCategories[i].id === this.taxonomyId)
|
||||
this.selectedCategories.splice(i, 1);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// this.$toast.open({
|
||||
// duration: 3000,
|
||||
// message: this.$i18n.get('info_error_deleting_taxonomy'),
|
||||
// position: 'is-bottom',
|
||||
// type: 'is-danger',
|
||||
// queue: true
|
||||
// });
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
deleteSelectedCategories() {
|
||||
this.$modal.open({
|
||||
parent: this,
|
||||
component: CustomDialog,
|
||||
props: {
|
||||
icon: 'alert',
|
||||
title: this.$i18n.get('label_warning'),
|
||||
message: this.$i18n.get('info_warning_selected_taxonomies_delete'),
|
||||
onConfirm: () => {
|
||||
|
||||
for (let i = 0; i < this.taxonomies.length; i++) {
|
||||
if (this.selectedCategories[i]) {
|
||||
this.deleteTaxonomy(this.taxonomies[i].id)
|
||||
.then(() => {
|
||||
// this.loadCategories();
|
||||
// this.$toast.open({
|
||||
// duration: 3000,
|
||||
// message: this.$i18n.get('info_taxonomy_deleted'),
|
||||
// position: 'is-bottom',
|
||||
// type: 'is-secondary',
|
||||
// queue: false
|
||||
// })
|
||||
}).catch(() => {
|
||||
// this.$toast.open({
|
||||
// duration: 3000,
|
||||
// message: this.$i18n.get('info_error_deleting_taxonomy'),
|
||||
// position: 'is-bottom',
|
||||
// type: 'is-danger',
|
||||
// queue: false
|
||||
// });
|
||||
});
|
||||
}
|
||||
}
|
||||
this.allCategoriesOnPageSelected = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
goToTaxonomyPage(taxonomyId) {
|
||||
this.$router.push(this.$routerHelper.getTaxonomyPath(taxonomyId));
|
||||
},
|
||||
goToTaxonomyEditPage(taxonomyId) {
|
||||
this.$router.push(this.$routerHelper.getTaxonomyEditPath(taxonomyId));
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@import "../../scss/_variables.scss";
|
||||
|
||||
.selection-control {
|
||||
|
||||
padding: 6px 0px 0px 13px;
|
||||
background: white;
|
||||
height: 40px;
|
||||
|
||||
.select-all {
|
||||
color: $gray-light;
|
||||
font-size: 14px;
|
||||
&:hover {
|
||||
color: $gray-light;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
|
@ -0,0 +1,236 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="primary-page page-container">
|
||||
<tainacan-title />
|
||||
<div
|
||||
class="sub-header"
|
||||
v-if="$userCaps.hasCapability('edit_tainacan-taxonomies')">
|
||||
<div class="header-item">
|
||||
<router-link
|
||||
id="button-create-taxonomy"
|
||||
tag="button"
|
||||
class="button is-secondary"
|
||||
:to="{ path: $routerHelper.getNewTaxonomyPath() }">
|
||||
{{ $i18n.getFrom('taxonomies', 'new_item') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="above-subheader">
|
||||
<div class="tabs">
|
||||
<ul>
|
||||
<li
|
||||
@click="onChangeTab('')"
|
||||
:class="{ 'is-active': status == undefined || status == ''}"><a>{{ $i18n.get('label_all_items') }}</a></li>
|
||||
<li
|
||||
@click="onChangeTab('draft')"
|
||||
:class="{ 'is-active': status == 'draft'}"><a>{{ $i18n.get('label_draft_items') }}</a></li>
|
||||
<li
|
||||
@click="onChangeTab('trash')"
|
||||
:class="{ 'is-active': status == 'trash'}"><a>{{ $i18n.get('label_trash_items') }}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<taxonomies-list
|
||||
:is-loading="isLoading"
|
||||
:total-taxonomies="totalCategories"
|
||||
:page="page"
|
||||
:taxonomies-per-page="taxonomiesPerPage"
|
||||
:taxonomies="taxonomies"/>
|
||||
|
||||
<!-- Empty state image -->
|
||||
<div v-if="totalCategories <= 0 && !isLoading">
|
||||
<section class="section">
|
||||
<div class="content has-text-grey has-text-centered">
|
||||
<p>
|
||||
<b-icon
|
||||
icon="inbox"
|
||||
size="is-large"/>
|
||||
</p>
|
||||
<p v-if="status == undefined || status == ''">{{ $i18n.get('info_no_taxonomy_created') }}</p>
|
||||
<p v-if="status == 'draft'">{{ $i18n.get('info_no_taxonomy_draft') }}</p>
|
||||
<p v-if="status == 'trash'">{{ $i18n.get('info_no_taxonomy_trash') }}</p>
|
||||
<router-link
|
||||
v-if="status == undefined || status == ''"
|
||||
id="button-create-taxonomy"
|
||||
tag="button"
|
||||
class="button is-primary"
|
||||
:to="{ path: $routerHelper.getNewTaxonomyPath() }">
|
||||
{{ $i18n.getFrom('taxonomies', 'new_item') }}
|
||||
</router-link>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<!-- Footer -->
|
||||
<div
|
||||
class="pagination-area"
|
||||
v-if="totalCategories > 0">
|
||||
<div class="shown-items">
|
||||
{{
|
||||
$i18n.get('info_showing_taxonomies') +
|
||||
(taxonomiesPerPage * (page - 1) + 1) +
|
||||
$i18n.get('info_to') +
|
||||
getLastTaxonomyNumber() +
|
||||
$i18n.get('info_of') + totalCategories + '.'
|
||||
}}
|
||||
</div>
|
||||
<div class="items-per-page">
|
||||
<b-field
|
||||
horizontal
|
||||
:label="$i18n.get('label_taxonomies_per_page')">
|
||||
<b-select
|
||||
:value="taxonomiesPerPage"
|
||||
@input="onChangeCategoriesPerPage"
|
||||
:disabled="taxonomies.length <= 0">
|
||||
<option value="12">12</option>
|
||||
<option value="24">24</option>
|
||||
<option value="48">48</option>
|
||||
<option value="96">96</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
</div>
|
||||
<div class="pagination">
|
||||
<b-pagination
|
||||
@change="onPageChange"
|
||||
:total="totalCategories"
|
||||
:current.sync="page"
|
||||
order="is-centered"
|
||||
size="is-small"
|
||||
:per-page="taxonomiesPerPage"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CategoriesList from "../../components/lists/taxonomies-list.vue";
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
//import moment from 'moment'
|
||||
|
||||
export default {
|
||||
name: 'CategoriesPage',
|
||||
data(){
|
||||
return {
|
||||
isLoading: false,
|
||||
totalCategories: 0,
|
||||
page: 1,
|
||||
taxonomiesPerPage: 12,
|
||||
status: ''
|
||||
}
|
||||
},
|
||||
components: {
|
||||
CategoriesList
|
||||
},
|
||||
methods: {
|
||||
...mapActions('taxonomy', [
|
||||
'fetchCategories',
|
||||
]),
|
||||
...mapGetters('taxonomy', [
|
||||
'getCategories'
|
||||
]),
|
||||
onChangeTab(status) {
|
||||
this.status = status;
|
||||
this.loadCategories();
|
||||
},
|
||||
onChangeCategoriesPerPage(value) {
|
||||
this.taxonomiesPerPage = value;
|
||||
this.$userPrefs.set('taxonomies_per_page', value)
|
||||
.then((newValue) => {
|
||||
this.taxonomiesPerPage = newValue;
|
||||
})
|
||||
.catch(() => {
|
||||
this.$console.log("Error settings user prefs for taxonomies per page")
|
||||
});
|
||||
this.loadCategories();
|
||||
},
|
||||
onPageChange(page) {
|
||||
this.page = page;
|
||||
this.loadCategories();
|
||||
},
|
||||
loadCategories() {
|
||||
this.isLoading = true;
|
||||
|
||||
this.fetchCategories({ 'page': this.page, 'taxonomiesPerPage': this.taxonomiesPerPage, 'status': this.status })
|
||||
.then((res) => {
|
||||
this.isLoading = false;
|
||||
this.totalCategories = res.total;
|
||||
})
|
||||
.catch(() => {
|
||||
this.isLoading = false;
|
||||
});
|
||||
},
|
||||
getLastTaxonomyNumber() {
|
||||
let last = (Number(this.taxonomiesPerPage * (this.page - 1)) + Number(this.taxonomiesPerPage));
|
||||
return last > this.totalCategories ? this.totalCategories : last;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
taxonomies(){
|
||||
return this.getCategories();
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.taxonomiesPerPage = this.$userPrefs.get('taxonomies_per_page');
|
||||
},
|
||||
mounted(){
|
||||
this.$userPrefs.fetch('taxonomies_per_page')
|
||||
.then((value) => {
|
||||
if (this.taxonomiesPerPage != value) {
|
||||
this.taxonomiesPerPage = value;
|
||||
this.loadCategories;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.$userPrefs.set('taxonomies_per_page', 12);
|
||||
});
|
||||
this.loadCategories();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../scss/_variables.scss';
|
||||
|
||||
.sub-header {
|
||||
max-height: $subheader-height;
|
||||
height: $subheader-height;
|
||||
margin-left: -$page-side-padding;
|
||||
margin-right: -$page-side-padding;
|
||||
margin-top: -$page-top-padding;
|
||||
padding-top: $page-small-top-padding;
|
||||
padding-left: $page-side-padding;
|
||||
padding-right: $page-side-padding;
|
||||
border-bottom: 1px solid #ddd;
|
||||
|
||||
.header-item {
|
||||
display: inline-block;
|
||||
padding-right: 8em;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 769px) {
|
||||
height: 60px;
|
||||
margin-top: -0.5em;
|
||||
padding-top: 0.9em;
|
||||
|
||||
.header-item {
|
||||
padding-right: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tabs {
|
||||
padding-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
padding-left: $page-side-padding;
|
||||
padding-right: $page-side-padding;
|
||||
}
|
||||
.above-subheader {
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
<template>
|
||||
<div class="columns is-fullheight">
|
||||
<div class="page-container primary-page">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<p class="title">
|
||||
{{ taxonomy.name }}
|
||||
</p>
|
||||
<p class="subtitle">
|
||||
{{ taxonomy.description }}
|
||||
</p>
|
||||
</div>
|
||||
<footer class="card-footer">
|
||||
<router-link
|
||||
class="card-footer-item"
|
||||
:to="{ path: $routerHelper.getTaxonomyEditPath(taxonomyId)}">
|
||||
{{ $i18n.getFrom('taxonomies','edit_item') }}
|
||||
</router-link>
|
||||
<a class="card-footer-item">
|
||||
Edit terms
|
||||
</a>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: 'TaxonomyPage',
|
||||
data(){
|
||||
return {
|
||||
taxonomyId: Number,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
...mapActions('taxonomy', [
|
||||
'fetchTaxonomy'
|
||||
]),
|
||||
...mapGetters('taxonomy', [
|
||||
'getTaxonomy'
|
||||
])
|
||||
},
|
||||
computed: {
|
||||
taxonomy(){
|
||||
return this.getTaxonomy();
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.taxonomyId = parseInt(this.$route.params.taxonomyId);
|
||||
|
||||
this.fetchTaxonomy(this.taxonomyId);
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
|
@ -0,0 +1,129 @@
|
|||
<template>
|
||||
<div class="block">
|
||||
<div
|
||||
v-for="(option,index) in getOptions(0)"
|
||||
:key="index"
|
||||
:value="index"
|
||||
class="control">
|
||||
<b-checkbox
|
||||
:style="{ paddingLeft: (option.level * 30) + 'px' }"
|
||||
v-model="selected"
|
||||
:native-value="option.id"
|
||||
>{{ option.name }}</b-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { tainacan as axios } from '../../../js/axios/axios';
|
||||
|
||||
export default {
|
||||
created(){
|
||||
this.collection = ( this.collection_id ) ? this.collection_id : this.filter.collection_id;
|
||||
this.metadatum = ( this.metadatum_id ) ? this.metadatum_id : this.filter.metadatum.metadatum_id ;
|
||||
this.type = ( this.filter_type ) ? this.filter_type : this.filter.metadatum.metadata_type;
|
||||
this.loadOptions();
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
isLoading: false,
|
||||
options: [],
|
||||
type: '',
|
||||
collection: '',
|
||||
metadatum: '',
|
||||
selected: [],
|
||||
taxonomy: ''
|
||||
}
|
||||
},
|
||||
props: {
|
||||
filter: {
|
||||
type: Object // concentrate all attributes metadatum id and type
|
||||
},
|
||||
metadatum_id: [Number], // not required, but overrides the filter metadatum id if is set
|
||||
collection_id: [Number], // not required, but overrides the filter metadatum id if is set
|
||||
filter_type: [String], // not required, but overrides the filter metadatum type if is set
|
||||
id: '',
|
||||
query: {
|
||||
type: Object // concentrate all attributes metadatum id and type
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selected: function(val){
|
||||
this.selected = val;
|
||||
this.onSelect();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getValuesTaxonomy( taxonomy ){
|
||||
return axios.get('/taxonomy/' + taxonomy + '/terms?hideempty=0&order=asc' ).then( res => {
|
||||
for (let item of res.data) {
|
||||
this.taxonomy = item.taxonomy;
|
||||
this.options.push(item);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.$console.log(error);
|
||||
});
|
||||
},
|
||||
loadOptions(){
|
||||
let promise = null;
|
||||
this.isLoading = true;
|
||||
|
||||
axios.get('/collection/'+ this.collection +'/metadata/' + this.metadatum)
|
||||
.then( res => {
|
||||
let metadatum = res.data;
|
||||
promise = this.getValuesTaxonomy( metadatum.metadata_type_options.taxonomy_id );
|
||||
|
||||
promise.then( () => {
|
||||
this.isLoading = false;
|
||||
this.selectedValues()
|
||||
})
|
||||
.catch( error => {
|
||||
this.$console.log('error select', error );
|
||||
this.isLoading = false;
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
this.$console.log(error);
|
||||
});
|
||||
},
|
||||
getOptions( parent, level = 0 ){ // retrieve only ids
|
||||
let result = [];
|
||||
if ( this.options ){
|
||||
for( let term of this.options ){
|
||||
if( term.parent == parent ){
|
||||
term['level'] = level;
|
||||
result.push( term );
|
||||
const levelTerm = level + 1;
|
||||
const children = this.getOptions( term.id, levelTerm);
|
||||
result = result.concat( children );
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
selectedValues(){
|
||||
if ( !this.query || !this.query.taxquery || !Array.isArray( this.query.taxquery ) )
|
||||
return false;
|
||||
|
||||
let index = this.query.taxquery.findIndex(newMetadatum => newMetadatum.taxonomy === this.taxonomy );
|
||||
if ( index >= 0){
|
||||
let metadata = this.query.taxquery[ index ];
|
||||
this.selected = metadata.terms;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSelect(){
|
||||
this.$emit('input', {
|
||||
filter: 'selectbox',
|
||||
taxonomy: this.taxonomy,
|
||||
compare: 'IN',
|
||||
metadatum_id: this.metadatum,
|
||||
collection_id: this.collection,
|
||||
terms: this.selected
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,131 @@
|
|||
<template>
|
||||
<div class="block">
|
||||
<b-select
|
||||
:id = "id"
|
||||
:loading = "isLoading"
|
||||
v-model = "selected"
|
||||
@input = "onSelect()"
|
||||
size="is-small"
|
||||
expanded>
|
||||
<option value="">{{ $i18n.get('label_selectbox_init') }}...</option>
|
||||
<option
|
||||
v-for=" (option, index) in options"
|
||||
:key="index"
|
||||
:label="option.name"
|
||||
:value="option.id">{{ option.name }}</option>
|
||||
</b-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { tainacan as axios } from '../../../js/axios/axios';
|
||||
|
||||
export default {
|
||||
created(){
|
||||
this.collection = ( this.collection_id ) ? this.collection_id : this.filter.collection_id;
|
||||
this.metadatum = ( this.metadatum_id ) ? this.metadatum_id : this.filter.metadatum.metadatum_id ;
|
||||
this.type = ( this.filter_type ) ? this.filter_type : this.filter.metadatum.metadata_type;
|
||||
this.loadOptions();
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
isLoading: false,
|
||||
options: [],
|
||||
collection: '',
|
||||
metadatum: '',
|
||||
selected: '',
|
||||
taxonomy: ''
|
||||
}
|
||||
},
|
||||
props: {
|
||||
filter: {
|
||||
type: Object // concentrate all attributes metadatum id and type
|
||||
},
|
||||
metadatum_id: [Number], // not required, but overrides the filter metadatum id if is set
|
||||
collection_id: [Number], // not required, but overrides the filter metadatum id if is set
|
||||
filter_type: [String], // not required, but overrides the filter metadatum type if is set
|
||||
id: '',
|
||||
query: {
|
||||
type: Object // concentrate all attributes metadatum id and type
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
selected: function(val){
|
||||
this.selected = val;
|
||||
this.onSelect();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getValuesTaxonomy( taxonomy ){
|
||||
return axios.get('/taxonomy/' + taxonomy + '/terms?hideempty=0' ).then( res => {
|
||||
for (let item of res.data) {
|
||||
this.taxonomy = item.taxonomy;
|
||||
this.options.push(item);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.$console.log(error);
|
||||
});
|
||||
},
|
||||
loadOptions(){
|
||||
let promise = null;
|
||||
this.isLoading = true;
|
||||
|
||||
axios.get('/collection/'+ this.collection +'/metadata/' + this.metadatum)
|
||||
.then( res => {
|
||||
let metadatum = res.data;
|
||||
promise = this.getValuesTaxonomy( metadatum.metadata_type_options.taxonomy_id );
|
||||
|
||||
promise.then( () => {
|
||||
this.isLoading = false;
|
||||
this.selectedValues();
|
||||
})
|
||||
.catch( error => {
|
||||
this.$console.log('error select', error );
|
||||
this.isLoading = false;
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
this.$console.log(error);
|
||||
});
|
||||
},
|
||||
getOptions( parent, level = 0 ){ // retrieve only ids
|
||||
let result = [];
|
||||
if ( this.options ){
|
||||
for( let term of this.options ){
|
||||
if( term.parent == parent ){
|
||||
term['level'] = level;
|
||||
result.push( term );
|
||||
const levelTerm = level + 1;
|
||||
const children = this.getOptions( term.id, levelTerm);
|
||||
result = result.concat( children );
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
selectedValues(){
|
||||
if ( !this.query || !this.query.taxquery || !Array.isArray( this.query.taxquery ) )
|
||||
return false;
|
||||
|
||||
let index = this.query.taxquery.findIndex(newMetadatum => newMetadatum.taxonomy === this.taxonomy );
|
||||
if ( index >= 0){
|
||||
let metadata = this.query.taxquery[ index ];
|
||||
this.selected = metadata.terms;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
onSelect(){
|
||||
this.$emit('input', {
|
||||
filter: 'selectbox',
|
||||
compare: 'IN',
|
||||
taxonomy: this.taxonomy,
|
||||
metadatum_id: this.metadatum,
|
||||
collection_id: this.collection,
|
||||
terms: this.selected
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,142 @@
|
|||
<template>
|
||||
<div class="block">
|
||||
<b-taginput
|
||||
size="is-small"
|
||||
v-model="selected"
|
||||
:data="options"
|
||||
:loading="isLoading"
|
||||
autocomplete
|
||||
field="label"
|
||||
attached
|
||||
:class="{'has-selected': selected != undefined && selected != []}"
|
||||
@typing="search" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { tainacan as axios } from '../../../js/axios/axios'
|
||||
|
||||
export default {
|
||||
created(){
|
||||
this.collection = ( this.collection_id ) ? this.collection_id : this.filter.collection_id;
|
||||
this.metadatum = ( this.metadatum_id ) ? this.metadatum_id : this.filter.metadatum.metadatum_id ;
|
||||
this.type = ( this.filter_type ) ? this.filter_type : this.filter.metadatum.metadata_type;
|
||||
|
||||
let in_route = '/collection/' + this.collection + '/metadata/' + this.metadatum;
|
||||
|
||||
if(this.isRepositoryLevel || this.collection == 'filter_in_repository'){
|
||||
in_route = '/metadata/'+ this.metadatum;
|
||||
}
|
||||
|
||||
axios.get(in_route)
|
||||
.then( res => {
|
||||
let metadatum = res.data;
|
||||
this.selectedValues( metadatum.metadata_type_options.taxonomy_id );
|
||||
});
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
results:'',
|
||||
selected:[],
|
||||
options: [],
|
||||
isLoading: false,
|
||||
type: '',
|
||||
collection: '',
|
||||
metadatum: '',
|
||||
taxonomy: ''
|
||||
}
|
||||
},
|
||||
props: {
|
||||
filter: {
|
||||
type: Object // concentrate all attributes metadatum id and type
|
||||
},
|
||||
metadatum_id: [Number], // not required, but overrides the filter metadatum id if is set
|
||||
collection_id: [Number], // not required, but overrides the filter metadatum id if is set
|
||||
filter_type: [String], // not required, but overrides the filter metadatum type if is set
|
||||
id: '',
|
||||
query: {
|
||||
type: Object // concentrate all attributes metadatum id and type
|
||||
},
|
||||
isRepositoryLevel: Boolean,
|
||||
},
|
||||
watch: {
|
||||
selected( value ){
|
||||
this.selected = value;
|
||||
let values = [];
|
||||
if( this.selected.length > 0 ){
|
||||
for(let val of this.selected){
|
||||
values.push( val.value );
|
||||
}
|
||||
}
|
||||
this.$emit('input', {
|
||||
filter: 'taginput',
|
||||
compare: 'IN',
|
||||
taxonomy: this.taxonomy,
|
||||
metadatum_id: ( this.metadatum_id ) ? this.metadatum_id : this.filter.metadatum,
|
||||
collection_id: ( this.collection_id ) ? this.collection_id : this.filter.collection_id,
|
||||
terms: values
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
search( query ){
|
||||
let promise = null;
|
||||
this.options = [];
|
||||
const q = query;
|
||||
const endpoint = this.isRepositoryLevel ? '/metadata/' + this.metadatum : '/collection/'+ this.collection +'/metadata/' + this.metadatum;
|
||||
|
||||
axios.get(endpoint)
|
||||
.then( res => {
|
||||
let metadatum = res.data;
|
||||
promise = this.getValuesTaxonomy( metadatum.metadata_type_options.taxonomy_id, q );
|
||||
this.isLoading = true;
|
||||
promise.then( () => {
|
||||
this.isLoading = false;
|
||||
})
|
||||
.catch( error => {
|
||||
this.$console.log('error select', error );
|
||||
this.isLoading = false;
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
this.$console.log(error);
|
||||
});
|
||||
},
|
||||
getValuesTaxonomy( taxonomy, query ){
|
||||
return axios.get('/taxonomy/' + taxonomy + '/terms?hideempty=0&order=asc' ).then( res => {
|
||||
for (let term of res.data) {
|
||||
if( term.name.toLowerCase().indexOf( query.toLowerCase() ) >= 0 ){
|
||||
this.taxonomy = term.taxonomy;
|
||||
this.options.push({label: term.name, value: term.id});
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.$console.log(error);
|
||||
});
|
||||
},
|
||||
selectedValues( taxonomy ){
|
||||
if ( !this.query || !this.query.taxquery || !Array.isArray( this.query.taxquery ) )
|
||||
return false;
|
||||
|
||||
let index = this.query.taxquery.findIndex(newMetadatum => newMetadatum.taxonomy === this.taxonomy );
|
||||
if ( index >= 0){
|
||||
let metadata = this.query.taxquery[ index ];
|
||||
for ( let id of metadata.terms ){
|
||||
this.getTerm( taxonomy, id );
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
getTerm( taxonomy, id ){
|
||||
return axios.get('/taxonomy/' + taxonomy + '/terms/' + id + '?order=asc&hideempty=0' ).then( res => {
|
||||
this.$console.log(res);
|
||||
})
|
||||
.catch(error => {
|
||||
this.$console.log(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
namespace Tainacan\Filter_Types;
|
||||
|
||||
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
|
||||
|
||||
/**
|
||||
* Class TainacanMetadatumType
|
||||
*/
|
||||
class TaxonomyCheckbox extends Filter_Type {
|
||||
|
||||
function __construct(){
|
||||
$this->set_supported_types(['term']);
|
||||
$this->set_component('tainacan-filter-taxonomy-checkbox');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $filter
|
||||
* @return string
|
||||
*/
|
||||
|
||||
public function render( $filter ){
|
||||
return '<tainacan-filter-taxonomy-checkbox name="'.$filter->get_name().'"
|
||||
filter_type="'.$filter->get_metadatum()->get_metadata_type().'"
|
||||
collection_id="'.$filter->get_collection_id().'"
|
||||
metadatum_id="'.$filter->get_metadatum()->get_id().'"></tainacan-filter-checkbox>';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
namespace Tainacan\Filter_Types;
|
||||
|
||||
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
|
||||
|
||||
/**
|
||||
* Class TainacanMetadatumType
|
||||
*/
|
||||
class TaxonomySelectbox extends Filter_Type {
|
||||
|
||||
function __construct(){
|
||||
$this->set_supported_types(['term']);
|
||||
$this->set_component('tainacan-filter-taxonomy-selectbox');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $filter
|
||||
* @return string
|
||||
*/
|
||||
|
||||
public function render( $filter ){
|
||||
return '<tainacan-filter-taxonomy-selectbox name="'.$filter->get_name().'"
|
||||
filter_type="'.$filter->get_metadatum()->get_metadata_type().'"
|
||||
collection_id="'.$filter->get_collection_id().'"
|
||||
metadatum_id="'.$filter->get_metadatum()->get_id().'"></tainacan-filter-selectbox>';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
namespace Tainacan\Filter_Types;
|
||||
|
||||
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
|
||||
|
||||
/**
|
||||
* Class Taginput
|
||||
*/
|
||||
class TaxonomyTaginput extends Filter_Type {
|
||||
|
||||
function __construct(){
|
||||
$this->set_supported_types(['term']);
|
||||
$this->set_component('tainacan-filter-taxonomy-taginput');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $filter
|
||||
* @return string
|
||||
*/
|
||||
|
||||
public function render( $filter ){
|
||||
return '<tainacan-filter-taxonomy-taginput name="'.$filter->get_name().'"
|
||||
filter_type="'.$filter->get_metadatum()->get_metadata_type().'"
|
||||
collection_id="'.$filter->get_collection_id().'"
|
||||
metadatum_id="'.$filter->get_metadatum()->get_id().'"></tainacan-filter-taginput>';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
<template>
|
||||
<div>
|
||||
<span>
|
||||
<a
|
||||
class="button"
|
||||
@click="showForm = !showForm"><b-icon
|
||||
size="is-small"
|
||||
icon="plus"/> {{ $i18n.get('label_new_term') }}</a>
|
||||
</span>
|
||||
<div class="columns">
|
||||
<transition name="fade">
|
||||
|
||||
<section
|
||||
v-if="showForm"
|
||||
class="column is-one-third"
|
||||
style="padding-left: 0px;">
|
||||
|
||||
<b-field :label="$i18n.get('label_name')">
|
||||
<b-input
|
||||
:class="{'has-content': name != undefined && name != ''}"
|
||||
v-model="name"/>
|
||||
</b-field>
|
||||
|
||||
<b-field :label="$i18n.get('label_parent_term')">
|
||||
<b-select
|
||||
v-model="parent">
|
||||
<option
|
||||
:value="0"
|
||||
selected> ---{{ $i18n.get('label_parent_term') }}--- </option>
|
||||
<option
|
||||
v-for="(option,index) in options"
|
||||
:key="index"
|
||||
:value="option.id"
|
||||
v-html="setSpaces( option.level ) + option.name"/>
|
||||
</b-select>
|
||||
</b-field>
|
||||
|
||||
<a
|
||||
class="button is-primary"
|
||||
@click="save">{{ $i18n.get('save') }}</a>
|
||||
</section>
|
||||
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
<script>
|
||||
import { tainacan as axios } from '../../../js/axios/axios'
|
||||
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
name: '',
|
||||
parent: 0,
|
||||
showForm: false,
|
||||
metadatum_id: this.metadatum.metadatum.id
|
||||
}
|
||||
},
|
||||
props: {
|
||||
id: String,
|
||||
item_id: [Number,String],
|
||||
metadatum: [Number,String],
|
||||
taxonomy_id: [Number,String],
|
||||
value:[ Array, Boolean, Number ],
|
||||
options: {
|
||||
type: Array
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setSpaces( level ){
|
||||
let result = '';
|
||||
let space = ' '
|
||||
|
||||
for(let i = 0;i < level; i++)
|
||||
result += space;
|
||||
|
||||
return result;
|
||||
},
|
||||
save(){
|
||||
if( this.name.trim() === ''){
|
||||
this.$toast.open({
|
||||
duration: 2000,
|
||||
message: this.$i18n.get('info_name_is_required'),
|
||||
position: 'is-bottom',
|
||||
type: 'is-danger'
|
||||
})
|
||||
} else {
|
||||
const instance = this;
|
||||
|
||||
axios.post(`/taxonomy/${this.taxonomy_id}/terms?hideempty=0&order=asc`, {
|
||||
name: this.name,
|
||||
parent: this.parent
|
||||
})
|
||||
.then( res => {
|
||||
instance.name = '';
|
||||
instance.parent = 0;
|
||||
|
||||
if( res.data && res.data.id || res.id ){
|
||||
let id = ( res.id ) ? res.id : res.data.id;
|
||||
let val = this.value;
|
||||
|
||||
if( !Array.isArray( val ) && this.metadatum.metadatum.multiple === 'no' ){
|
||||
axios.patch(`/item/${this.item_id}/metadata/${this.metadatum_id}`, {
|
||||
values: id,
|
||||
}).then(() => {
|
||||
instance.$emit('newTerm', id);
|
||||
})
|
||||
} else {
|
||||
val = ( val ) ? val : [];
|
||||
val.push( id );
|
||||
axios.patch(`/item/${this.item_id}/metadata/${this.metadatum_id}`, {
|
||||
values: val,
|
||||
}).then( () => {
|
||||
instance.$emit('newTerm', val);
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
button{
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,197 @@
|
|||
<template>
|
||||
<section
|
||||
v-if="isReady"
|
||||
:listen="setError">
|
||||
<b-field
|
||||
:addons="false"
|
||||
:type="taxonomyType"
|
||||
:message="taxonomyMessage">
|
||||
<label class="label is-inline">
|
||||
{{ $i18n.get('label_select_taxonomy') }}<span :class="taxonomyType" > * </span>
|
||||
<help-button
|
||||
:title="$i18n.getHelperTitle('tainacan-taxonomy', 'taxonomy_id')"
|
||||
:message="$i18n.getHelperMessage('tainacan-taxonomy', 'taxonomy_id')"/>
|
||||
</label>
|
||||
<b-select
|
||||
name="field_type_options[taxonomy_id]"
|
||||
placeholder="Select the taxonomy"
|
||||
v-model="taxonomy_id"
|
||||
@input="emitValues()"
|
||||
@focus="clear"
|
||||
:loading="loading">
|
||||
<option value="">{{ $i18n.get('label_selectbox_init') }}...</option>
|
||||
<option
|
||||
v-for="option in taxonomies"
|
||||
:value="option.id"
|
||||
:key="option.id">
|
||||
{{ option.name }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
|
||||
<b-field :addons="false">
|
||||
<label class="label">
|
||||
{{ $i18n.get('label_select_taxonomy_input_type') }}
|
||||
<help-button
|
||||
:title="$i18n.getHelperTitle('tainacan-taxonomy', 'input_type')"
|
||||
:message="$i18n.getHelperMessage('tainacan-taxonomy', 'input_type')"/>
|
||||
</label>
|
||||
<b-select
|
||||
v-if="listInputType"
|
||||
name="metadata_type_options[component_type]"
|
||||
placeholder="Select the input type for the taxonomy metadatum"
|
||||
@input="emitValues()"
|
||||
v-model="input_type">
|
||||
<option
|
||||
v-for="(option, index) in single_types"
|
||||
:value="index"
|
||||
:key="index">
|
||||
{{ option }}
|
||||
</option>
|
||||
</b-select>
|
||||
|
||||
<b-select
|
||||
name="metadata_type_options[input_type]"
|
||||
placeholder="Select the input type for the taxonomy metadatum"
|
||||
v-model="input_type"
|
||||
@input="emitValues()"
|
||||
v-else>
|
||||
|
||||
<option
|
||||
v-for="(option, index) in multiple_types"
|
||||
:value="index"
|
||||
:key="index">
|
||||
{{ option }}
|
||||
</option>
|
||||
</b-select>
|
||||
|
||||
</b-field>
|
||||
|
||||
<b-field :addons="false">
|
||||
<label class="label">
|
||||
{{ $i18n.get('label_taxonomy_allow_new_terms') }}
|
||||
<help-button
|
||||
:title="$i18n.getHelperTitle('tainacan-taxonomy', 'allow_new_terms')"
|
||||
:message="$i18n.getHelperMessage('tainacan-taxonomy', 'allow_new_terms')"/>
|
||||
</label>
|
||||
<div class="block">
|
||||
<b-checkbox
|
||||
v-model="allow_new_terms"
|
||||
@input="emitValues()"
|
||||
true-value="yes"
|
||||
false-value="no">
|
||||
{{ labelNewTerms() }}
|
||||
</b-checkbox>
|
||||
</div>
|
||||
</b-field>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { tainacan as axios } from '../../../js/axios/axios';
|
||||
import BCheckbox from "../../../../node_modules/buefy/src/components/checkbox/Checkbox.vue";
|
||||
|
||||
export default {
|
||||
components: {BCheckbox},
|
||||
props: {
|
||||
value: [ String, Object, Array ],
|
||||
metadatum: [ String, Object ],
|
||||
errors: [ String, Object, Array ]
|
||||
},
|
||||
created(){
|
||||
this.fetchTaxonomies().then(() => {
|
||||
if ( this.value ) {
|
||||
this.taxonomy_id = this.value.taxonomy_id;
|
||||
}
|
||||
});
|
||||
|
||||
if( this.value ) {
|
||||
this.allow_new_terms = ( this.value.allow_new_terms ) ? this.value.allow_new_terms : 'no';
|
||||
}
|
||||
|
||||
this.single_types['tainacan-taxonomy-radio'] = 'Radio';
|
||||
this.single_types['tainacan-taxonomy-selectbox'] = 'Selectbox';
|
||||
this.multiple_types['tainacan-taxonomy-tag-input'] = 'Tag Input';
|
||||
this.multiple_types['tainacan-taxonomy-checkbox'] = 'Checkbox';
|
||||
|
||||
this.isReady = true;
|
||||
},
|
||||
computed: {
|
||||
listInputType(){
|
||||
if( this.metadatum && this.metadatum.multiple === 'no' ){
|
||||
let types = Object.keys( this.single_types );
|
||||
let hasValue = this.value && this.value.input_type && types.indexOf( this.value.input_type ) >= 0;
|
||||
this.setInputType( ( hasValue ) ? this.value.input_type : 'tainacan-taxonomy-radio' );
|
||||
return true;
|
||||
} else {
|
||||
let types = Object.keys( this.multiple_types );
|
||||
let hasValue = this.value && this.value.input_type && types.indexOf( this.value.input_type ) >= 0;
|
||||
this.setInputType( ( hasValue ) ? this.value.input_type : 'tainacan-taxonomy-checkbox' );
|
||||
return false;
|
||||
}
|
||||
},
|
||||
setError(){
|
||||
if( this.errors && this.errors.taxonomy_id !== '' ){
|
||||
this.setErrorsAttributes( 'is-danger', this.errors.taxonomy_id );
|
||||
} else {
|
||||
this.setErrorsAttributes( '', '' );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
isReady: false,
|
||||
taxonomies: [],
|
||||
taxonomy_id: '',
|
||||
loading: true,
|
||||
allow_new_terms: 'yes',
|
||||
input_type: 'tainacan-taxonomy-radio',
|
||||
multiple_types: {},
|
||||
single_types: {},
|
||||
taxonomyType:'',
|
||||
taxonomyMessage: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setInputType( input ){
|
||||
this.input_type = input;
|
||||
},
|
||||
setErrorsAttributes( type, message ){
|
||||
this.taxonomyType = type;
|
||||
this.taxonomyMessage = message;
|
||||
},
|
||||
fetchTaxonomies(){
|
||||
return axios.get('/taxonomies')
|
||||
.then(res => {
|
||||
let taxonomies = res.data;
|
||||
this.loading = false;
|
||||
|
||||
if( taxonomies ){
|
||||
this.taxonomies = taxonomies;
|
||||
} else {
|
||||
this.taxonomies = [];
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.$console.log(error);
|
||||
});
|
||||
},
|
||||
labelNewTerms(){
|
||||
return ( this.allow_new_terms === 'yes' ) ? this.$i18n.get('label_yes') : this.$i18n.get('label_no');
|
||||
},
|
||||
clear(){
|
||||
this.taxonomyType = '';
|
||||
this.taxonomyMessage = '';
|
||||
},
|
||||
emitValues(){
|
||||
this.$emit('input',{
|
||||
taxonomy_id: this.taxonomy_id,
|
||||
input_type: this.input_type,
|
||||
allow_new_terms: this.allow_new_terms
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,144 @@
|
|||
<template>
|
||||
<div>
|
||||
<component
|
||||
:is="getComponent()"
|
||||
v-model="valueComponent"
|
||||
:allow-new="allowNew"
|
||||
:terms="terms"
|
||||
:options="getOptions(0)"/>
|
||||
<add-new-term
|
||||
class="add-new-term"
|
||||
v-if="getComponent() !== 'tainacan-taxonomy-tag-input' && allowNew"
|
||||
:taxonomy_id="taxonomy"
|
||||
:metadatum="metadatum"
|
||||
:item_id="metadatum.item.id"
|
||||
:value="valueComponent"
|
||||
:options="getOptions(0)"
|
||||
@newTerm="reload"/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { tainacan as axios } from '../../../js/axios/axios'
|
||||
import TainacanTaxonomyRadio from './TaxonomyRadio.vue'
|
||||
import TainacanTaxonomyCheckbox from './TaxonomyCheckbox.vue'
|
||||
import TainacanTaxonomyTagInput from './TaxonomyTaginput.vue'
|
||||
import TainacanTaxonomySelectbox from './TaxonomySelectbox.vue'
|
||||
import AddNewTerm from './AddNewTerm.vue'
|
||||
|
||||
export default {
|
||||
created(){
|
||||
let metadata_type_options = this.metadatum.metadatum.metadata_type_options;
|
||||
this.component = ( metadata_type_options && metadata_type_options.input_type )
|
||||
? this.metadatum.metadatum.metadata_type_options.input_type : this.componentAttribute
|
||||
|
||||
this.collectionId = this.metadatum.metadatum.collection_id;
|
||||
this.taxonomy = metadata_type_options.taxonomy_id;
|
||||
|
||||
if( metadata_type_options && metadata_type_options.allow_new_terms ){
|
||||
this.allowNew = metadata_type_options.allow_new_terms === 'yes'
|
||||
}
|
||||
this.getTermsFromTaxonomy();
|
||||
this.getTermsId();
|
||||
},
|
||||
components: {
|
||||
TainacanTaxonomyRadio,
|
||||
TainacanTaxonomyCheckbox,
|
||||
TainacanTaxonomyTagInput,
|
||||
TainacanTaxonomySelectbox,
|
||||
AddNewTerm
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
valueComponent: null,
|
||||
component: '',
|
||||
collectionId: '',
|
||||
taxonomy: '',
|
||||
terms:[], // object with names
|
||||
allowNew: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
valueComponent( val ){
|
||||
this.valueComponent = val;
|
||||
this.$emit('input', val);
|
||||
this.$emit('blur');
|
||||
}
|
||||
},
|
||||
props: {
|
||||
metadatum: {
|
||||
type: Object
|
||||
},
|
||||
componentAttribute: {
|
||||
type: String
|
||||
},
|
||||
value: [ Number, String, Array,Object ],
|
||||
id: ''
|
||||
},
|
||||
methods: {
|
||||
getComponent(){
|
||||
if( this.metadatum.metadatum
|
||||
&& this.metadatum.metadatum.metadata_type_options && this.metadatum.metadatum.metadata_type_options.input_type ){
|
||||
return this.metadatum.metadatum.metadata_type_options.input_type;
|
||||
}
|
||||
},
|
||||
getTermsFromTaxonomy(){
|
||||
axios.get('/taxonomy/' + this.taxonomy + '/terms?hideempty=0&order=asc' ).then( res => {
|
||||
for (let item of res.data) {
|
||||
this.terms.push( item );
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.$console.log(error);
|
||||
});
|
||||
},
|
||||
getOptions( parent, level = 0 ){ // retrieve only ids
|
||||
let result = [];
|
||||
if ( this.terms ){
|
||||
for( let term of this.terms ){
|
||||
if( term.parent == parent ){
|
||||
term['level'] = level;
|
||||
result.push( term );
|
||||
const levelTerm = level + 1;
|
||||
const children = this.getOptions( term.id, levelTerm);
|
||||
result = result.concat( children );
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
getTermsId(){
|
||||
let values = [];
|
||||
if( this.value && this.value.length > 0){
|
||||
for( let term of this.value ){
|
||||
if( term && term.id)
|
||||
values.push(term.id);
|
||||
}
|
||||
}
|
||||
|
||||
if( values.length > 0 && this.metadatum.metadatum){
|
||||
this.valueComponent = ( this.metadatum.metadatum && this.metadatum.metadatum.multiple === 'no' ) ? values[0] : values
|
||||
}
|
||||
|
||||
},
|
||||
onInput($event) {
|
||||
this.inputValue = $event;
|
||||
this.$emit('input', this.inputValue);
|
||||
this.$emit('blur');
|
||||
},
|
||||
reload( val ){
|
||||
this.valueComponent = val;
|
||||
|
||||
this.terms = [];
|
||||
this.getTermsFromTaxonomy();
|
||||
this.getTermsId();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.add-new-term{
|
||||
margin-top: 15px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<div>
|
||||
<div
|
||||
v-for="(option, index) in options"
|
||||
:key="index">
|
||||
<b-checkbox
|
||||
:id="id"
|
||||
:style="{ paddingLeft: (option.level * 30) + 'px' }"
|
||||
:key="index"
|
||||
v-model="checked"
|
||||
@input="onChecked(option)"
|
||||
:native-value="option.id"
|
||||
border>
|
||||
{{ option.name }}
|
||||
</b-checkbox>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
created(){
|
||||
if( this.value && this.value.length > 0)
|
||||
this.checked = this.value;
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
checked: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value( val ){
|
||||
this.checked = val;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
options: {
|
||||
type: Array
|
||||
},
|
||||
value: [ Number, String, Array ]
|
||||
},
|
||||
methods: {
|
||||
onChecked() {
|
||||
this.$emit('blur');
|
||||
this.onInput(this.checked)
|
||||
},
|
||||
onInput($event) {
|
||||
this.inputValue = $event;
|
||||
this.$emit('input', this.inputValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,51 @@
|
|||
<template>
|
||||
<div>
|
||||
<div
|
||||
v-for="(option, index) in options"
|
||||
:key="index">
|
||||
<b-radio
|
||||
:id="id"
|
||||
:style="{ paddingLeft: (option.level * 30) + 'px' }"
|
||||
:key="index"
|
||||
v-model="checked"
|
||||
@input="onChecked(option)"
|
||||
:native-value="option.id"
|
||||
border>
|
||||
{{ option.name }}
|
||||
</b-radio>
|
||||
<br>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
checked: ( this.value ) ? this.value : ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value( val ){
|
||||
this.checked = val;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
options: {
|
||||
type: Array
|
||||
},
|
||||
value: [ Number, String, Array ]
|
||||
},
|
||||
methods: {
|
||||
onChecked() {
|
||||
this.$emit('blur');
|
||||
this.onInput(this.checked)
|
||||
},
|
||||
onInput($event) {
|
||||
this.inputValue = $event;
|
||||
this.$emit('input', this.inputValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,60 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="block">
|
||||
<b-select
|
||||
:id="id"
|
||||
v-model="selected"
|
||||
@input="emitChange()"
|
||||
:placeholder="$i18n.get('label_select_taxonomy')"
|
||||
expanded>
|
||||
<option
|
||||
v-for="(option, index) in options"
|
||||
:key="index"
|
||||
:value="option.id"
|
||||
v-html="setSpaces( option.level ) + option.name"/>
|
||||
</b-select>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
created(){
|
||||
if( this.value )
|
||||
this.selected = this.value;
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
selected: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value( val ){
|
||||
this.selected = val;
|
||||
}
|
||||
},
|
||||
props: {
|
||||
id: String,
|
||||
options: {
|
||||
type: Array
|
||||
},
|
||||
value: [ Number, String, Array ]
|
||||
},
|
||||
methods: {
|
||||
emitChange() {
|
||||
this.$emit('input', this.selected);
|
||||
this.$emit('blur');
|
||||
},
|
||||
setSpaces( level ){
|
||||
let result = '';
|
||||
let space = ' '
|
||||
|
||||
for(let i = 0;i < level; i++)
|
||||
result += space;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,83 @@
|
|||
<template>
|
||||
<div class="block">
|
||||
<b-taginput
|
||||
size="is-small"
|
||||
icon="magnify"
|
||||
:allow-new="allowNew"
|
||||
@input="emitChange"
|
||||
v-model="selected"
|
||||
:data="labels"
|
||||
field="label"
|
||||
attached
|
||||
:class="{'has-selected': selected != undefined && selected != []}"
|
||||
autocomplete
|
||||
@typing="search"/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
selected: [],
|
||||
labels: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
terms(){
|
||||
this.selectedValues();
|
||||
}
|
||||
},
|
||||
props: {
|
||||
terms: [ Number, String, Array ],
|
||||
options: {
|
||||
type: Array
|
||||
},
|
||||
value: [ Number, String, Array ],
|
||||
allowNew: [ Boolean ]
|
||||
},
|
||||
methods: {
|
||||
search( query ){
|
||||
if( this.terms && this.terms.length > 0 ){
|
||||
let result = this.terms.filter( ( item ) => {
|
||||
let name = item.name.toLowerCase();
|
||||
let q = query.toLowerCase();
|
||||
return ( name.indexOf(q) >= 0 )
|
||||
});
|
||||
this.labels = [];
|
||||
for( let term of result){
|
||||
this.labels.push({label: term.name, value: term.id})
|
||||
}
|
||||
}
|
||||
},
|
||||
selectedValues(){
|
||||
if( this.value && this.value.length > 0 && this.selected.length === 0){
|
||||
let result = this.terms.filter( ( item ) => {
|
||||
let id = item.id;
|
||||
return ( this.value.indexOf( id ) >= 0 )
|
||||
});
|
||||
|
||||
let selected = [];
|
||||
for( let term of result){
|
||||
selected.push({label: term.name, value: term.id})
|
||||
}
|
||||
this.selected = selected;
|
||||
}
|
||||
},
|
||||
emitChange(){
|
||||
let val = this.selected;
|
||||
let results = [];
|
||||
|
||||
for( let term of val ){
|
||||
if( term.value ){
|
||||
results.push( term.value );
|
||||
} else {
|
||||
results.push( term );
|
||||
}
|
||||
}
|
||||
|
||||
this.$emit('input', results);
|
||||
this.$emit('blur');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
|
||||
namespace Tainacan\Metadata_Types;
|
||||
|
||||
use Tainacan\Entities\Metadatum;
|
||||
use Tainacan\Entities\Item_Metadata_Entity;
|
||||
use Tainacan\Repositories\Metadata;
|
||||
|
||||
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
|
||||
|
||||
/**
|
||||
* Class TainacanMetadatumType
|
||||
*/
|
||||
class Taxonomy extends Metadata_Type {
|
||||
|
||||
function __construct(){
|
||||
// call metadatum type constructor
|
||||
parent::__construct();
|
||||
$this->set_primitive_type('term');
|
||||
|
||||
$this->set_default_options([
|
||||
'allow_new_terms' => false
|
||||
]);
|
||||
|
||||
$this->set_form_component('tainacan-form-taxonomy');
|
||||
$this->set_component('tainacan-taxonomy');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function get_form_labels(){
|
||||
return [
|
||||
'taxonomy_id' => [
|
||||
'title' => __( 'Collection Related', 'tainacan' ),
|
||||
'description' => __( 'Select the collection to fetch items', 'tainacan' ),
|
||||
],
|
||||
'input_type' => [
|
||||
'title' => __( 'Input type', 'tainacan' ),
|
||||
'description' => __( 'The html type of the terms list ', 'tainacan' ),
|
||||
],
|
||||
'allow_new_terms' => [
|
||||
'title' => __( 'Allow new terms', 'tainacan' ),
|
||||
'description' => __( 'Allows to create new terms', 'tainacan' ),
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $itemMetadata Item_Metadata_Entity The instace of the entity itemMetadata
|
||||
* @return string
|
||||
*/
|
||||
|
||||
public function render( $itemMetadata ){
|
||||
$options = ( isset( $this->get_options()['options'] ) ) ? $this->get_options()['options'] : '';
|
||||
return '<tainacan-selectbox
|
||||
options="' . $options . '"
|
||||
metadatum_id ="'.$itemMetadata->get_metadatum()->get_id().'"
|
||||
item_id="'.$itemMetadata->get_item()->get_id().'"
|
||||
value=\''.json_encode( $itemMetadata->get_value() ).'\'
|
||||
name="'.$itemMetadata->get_metadatum()->get_name().'"></tainacan-selectbox>';
|
||||
}
|
||||
|
||||
public function validate_options( Metadatum $metadatum) {
|
||||
|
||||
if ( !in_array($metadatum->get_status(), apply_filters('tainacan-status-require-validation', ['publish','future','private'])) )
|
||||
return true;
|
||||
|
||||
if (empty($this->get_option('taxonomy_id')))
|
||||
return ['taxonomy_id' => __('Please select a taxonomy', 'tainacan')];
|
||||
|
||||
$Tainacan_Metadata = Metadata::get_instance();
|
||||
|
||||
$taxonomy_metadata = $Tainacan_Metadata->fetch([
|
||||
'collection_id' => $metadatum->get_collection_id(),
|
||||
'metadata_type' => 'Tainacan\\Metadata_Types\\Taxonomy'
|
||||
], 'OBJECT');
|
||||
|
||||
$taxonomy_metadata = array_map(function ($metadatum_map) {
|
||||
$fto = $metadatum_map->get_metadata_type_object();
|
||||
return [ $metadatum_map->get_id() => $fto->get_option('taxonomy_id') ];
|
||||
}, $taxonomy_metadata);
|
||||
|
||||
if( is_array( $taxonomy_metadata ) ){
|
||||
foreach ($taxonomy_metadata as $metadatum_id => $taxonomy_metadatum) {
|
||||
if ( is_array( $taxonomy_metadatum ) && key($taxonomy_metadatum) != $metadatum->get_id()
|
||||
&& in_array($this->get_option('taxonomy_id'), $taxonomy_metadatum)) {
|
||||
return ['taxonomy_id' => __('You can not have 2 taxonomy metadata using the same taxonomy in a collection.', 'tainacan')];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate item based on metadatum type taxonomies options
|
||||
*
|
||||
* @param Item_Metadata_Entity $item_metadata
|
||||
*
|
||||
* @return bool Valid or not
|
||||
*/
|
||||
public function validate( Item_Metadata_Entity $item_metadata) {
|
||||
|
||||
$item = $item_metadata->get_item();
|
||||
|
||||
if ( !in_array($item->get_status(), apply_filters('tainacan-status-require-validation', ['publish','future','private'])) )
|
||||
return true;
|
||||
|
||||
$valid = true;
|
||||
|
||||
if (false === $this->get_option('allow_new_terms')) {
|
||||
$terms = $item_metadata->get_value();
|
||||
|
||||
if (false === $terms)
|
||||
return true;
|
||||
|
||||
if (!is_array($terms))
|
||||
$terms = array($terms);
|
||||
|
||||
foreach ($terms as $term) {
|
||||
if (is_object($term) && $term instanceof \Tainacan\Entities\Term) {
|
||||
$term = $term->get_id();
|
||||
}
|
||||
|
||||
if (!term_exists($term)) {
|
||||
$valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $valid;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the value of an Item_Metadata_Entity using a metadatum of this metadatum type as an html string
|
||||
* @param Item_Metadata_Entity $item_metadata
|
||||
* @return string The HTML representation of the value, containing one or multiple terms, separated by comma, linked to term page
|
||||
*/
|
||||
public function get_value_as_html(Item_Metadata_Entity $item_metadata) {
|
||||
|
||||
$value = $item_metadata->get_value();
|
||||
|
||||
$return = '';
|
||||
|
||||
if ( $item_metadata->is_multiple() ) {
|
||||
|
||||
$count = 1;
|
||||
$total = sizeof($value);
|
||||
|
||||
foreach ( $value as $term ) {
|
||||
if ( $term instanceof \Tainacan\Entities\Term ) {
|
||||
$return .= $term->_toHtml();
|
||||
}
|
||||
|
||||
$count ++;
|
||||
|
||||
if ( $count <= $total ) {
|
||||
$return .= ', ';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if ( $value instanceof \Tainacan\Entities\Term ) {
|
||||
$return .= $value->_toHtml();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
import axios from '../../../axios/axios'
|
||||
|
||||
// CATEGORIES
|
||||
export const createTaxonomy = ({commit}, taxonomy) => {
|
||||
return new Promise(( resolve, reject ) => {
|
||||
axios.tainacan.post('/taxonomies', {
|
||||
name: taxonomy.name,
|
||||
description: taxonomy.description,
|
||||
status: taxonomy.status,
|
||||
slug: taxonomy.slug,
|
||||
allow_insert: taxonomy.allowInsert
|
||||
})
|
||||
.then( res => {
|
||||
let taxonomy = res.data;
|
||||
commit('setTaxonomy', taxonomy);
|
||||
|
||||
resolve( taxonomy );
|
||||
})
|
||||
.catch(error => {
|
||||
reject( error.response );
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteTaxonomy = ({ commit }, taxonomyId) => {
|
||||
return new Promise(( resolve, reject ) => {
|
||||
axios.tainacan.delete(`/taxonomies/${taxonomyId}?permanently=${true}`)
|
||||
.then(res => {
|
||||
commit('deleteTaxonomy', res.data);
|
||||
|
||||
resolve( res );
|
||||
})
|
||||
.catch(error => {
|
||||
reject( error )
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const updateTaxonomy = ({ commit }, taxonomy) => {
|
||||
return new Promise(( resolve, reject ) => {
|
||||
axios.tainacan.patch(`/taxonomies/${taxonomy.taxonomyId}`, {
|
||||
name: taxonomy.name,
|
||||
description: taxonomy.description,
|
||||
status: taxonomy.status,
|
||||
slug: taxonomy.slug ? taxonomy.slug : '',
|
||||
allow_insert: taxonomy.allowInsert
|
||||
})
|
||||
.then( res => {
|
||||
let taxonomy = res.data;
|
||||
|
||||
commit('setTaxonomy', taxonomy);
|
||||
|
||||
resolve( taxonomy );
|
||||
})
|
||||
.catch(error => {
|
||||
reject({ error_message: error['response']['data'].error_message, errors: error['response']['data'].errors });
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchCategories = ({ commit }, { page, taxonomiesPerPage, status } ) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
let endpoint = `/taxonomies?paged=${page}&perpage=${taxonomiesPerPage}&context=edit`;
|
||||
|
||||
if (status != undefined && status != '')
|
||||
endpoint = endpoint + '&status=' + status;
|
||||
|
||||
axios.tainacan.get(endpoint)
|
||||
.then(res => {
|
||||
let taxonomies = res.data;
|
||||
|
||||
commit('setCategories', taxonomies);
|
||||
|
||||
resolve({
|
||||
'taxonomies': taxonomies,
|
||||
'total': res.headers['x-wp-total']
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchTaxonomy = ({ commit }, taxonomyId) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.tainacan.get(`/taxonomies/${taxonomyId}`)
|
||||
.then(res => {
|
||||
let taxonomy = res.data;
|
||||
|
||||
commit('setTaxonomy', taxonomy);
|
||||
|
||||
resolve({
|
||||
'taxonomy': taxonomy
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchTaxonomyName = ({ commit }, taxonomyId) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.tainacan.get(`/taxonomies/${taxonomyId}?fetch_only=name`)
|
||||
.then(res => {
|
||||
let name = res.data;
|
||||
|
||||
commit('setTaxonomyName');
|
||||
|
||||
resolve(name.name)
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error)
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
// TAXONOMY TERMS
|
||||
export const sendTerm = ({commit}, { taxonomyId, name, description, parent, headerImageId }) => {
|
||||
return new Promise(( resolve, reject ) => {
|
||||
axios.tainacan.post('/taxonomy/' + taxonomyId + '/terms/', {
|
||||
name: name,
|
||||
description: description,
|
||||
parent: parent,
|
||||
header_image_id: headerImageId,
|
||||
})
|
||||
.then( res => {
|
||||
let term = res.data;
|
||||
commit('setSingleTerm', term);
|
||||
resolve( term );
|
||||
})
|
||||
.catch(error => {
|
||||
reject({ error_message: error['response']['data'].error_message, errors: error['response']['data'].errors });
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteTerm = ({ commit }, { taxonomyId, termId }) => {
|
||||
return new Promise(( resolve, reject ) => {
|
||||
axios.tainacan.delete(`/taxonomy/${taxonomyId}/terms/${termId}?permanently=${true}`)
|
||||
.then(res => {
|
||||
let term = res.data;
|
||||
commit('deleteTerm', termId);
|
||||
resolve( term );
|
||||
})
|
||||
.catch(error => {
|
||||
reject({ error_message: error['response']['data'].error_message, errors: error['response']['data'].errors });
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const updateTerm = ({ commit }, { taxonomyId, termId, name, description, parent, headerImageId }) => {
|
||||
return new Promise(( resolve, reject ) => {
|
||||
axios.tainacan.patch(`/taxonomy/${taxonomyId}/terms/${termId}`, {
|
||||
name: name,
|
||||
description: description,
|
||||
parent: parent,
|
||||
header_image_id: headerImageId,
|
||||
})
|
||||
.then( res => {
|
||||
let term = res.data;
|
||||
commit('setSingleTerm', term);
|
||||
resolve( term );
|
||||
})
|
||||
.catch(error => {
|
||||
reject({ error_message: error['response']['data'].error_message, errors: error['response']['data'].errors });
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchTerms = ({ commit }, taxonomyId ) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
axios.tainacan.get(`/taxonomy/${taxonomyId}/terms/?hideempty=0&order=asc`)
|
||||
.then(res => {
|
||||
let terms = res.data;
|
||||
commit('setTerms', terms);
|
||||
resolve( terms );
|
||||
})
|
||||
.catch(error => {
|
||||
reject( error );
|
||||
});
|
||||
});
|
||||
};
|
|
@ -0,0 +1,15 @@
|
|||
export const getTaxonomy = state => {
|
||||
return state.taxonomy;
|
||||
};
|
||||
|
||||
export const getCategories = state => {
|
||||
return state.taxonomies;
|
||||
};
|
||||
|
||||
export const getTaxonomyName = state => {
|
||||
return state.taxonomyName;
|
||||
};
|
||||
|
||||
export const getTerms = state => {
|
||||
return state.terms;
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
import * as actions from './actions';
|
||||
import * as getters from './getters';
|
||||
import * as mutations from './mutations';
|
||||
|
||||
const state = {
|
||||
taxonomies: [],
|
||||
taxonomy: {},
|
||||
taxonomyName: String,
|
||||
terms: []
|
||||
};
|
||||
|
||||
export default {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions,
|
||||
getters
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
import Vue from 'vue';
|
||||
|
||||
// CATEGORIES
|
||||
export const setTaxonomy = (state, taxonomy) => {
|
||||
state.taxonomy = taxonomy;
|
||||
};
|
||||
|
||||
export const setCategories = (state, taxonomies) => {
|
||||
state.taxonomies = taxonomies;
|
||||
};
|
||||
|
||||
export const setTaxonomyName = (state, name) => {
|
||||
state.taxonomyName = name;
|
||||
};
|
||||
|
||||
export const deleteTaxonomy = ( state, taxonomy ) => {
|
||||
let index = state.taxonomies.findIndex(deletedTaxonomy => deletedTaxonomy.id === taxonomy.id);
|
||||
|
||||
if (index >= 0) {
|
||||
state.taxonomies.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
// TAXONOMY TERMS
|
||||
export const setSingleTerm = (state, term) => {
|
||||
|
||||
let index = state.terms.findIndex(updatedTerm => updatedTerm.id === term.id);
|
||||
if ( index >= 0){
|
||||
Vue.set( state.terms, index, term );
|
||||
} else {
|
||||
state.terms.push( term );
|
||||
}
|
||||
};
|
||||
|
||||
export const setTerms = (state, terms) => {
|
||||
state.terms = terms;
|
||||
};
|
||||
|
||||
export const deleteTerm = ( state, termId ) => {
|
||||
let index = state.terms.findIndex(deletedTerm => deletedTerm.id === termId);
|
||||
if (index >= 0) {
|
||||
state.terms.splice(index, 1);
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue