Merge branch 'develop' into feature/compound

This commit is contained in:
Leo Germani 2018-03-27 22:25:36 -03:00
commit d1b7587b2c
84 changed files with 7596 additions and 3126 deletions

16
.eslintrc.js Normal file
View File

@ -0,0 +1,16 @@
module.exports = {
extends: [
// add more generic rulesets here, such as:
'eslint:recommended',
'plugin:vue/strongly-recommended'
],
rules: {
// override/add rules settings here, such as:
'vue/no-unused-vars': 'error',
"no-console": "warn",
"no-unused-vars": "warn",
"no-undef": "warn",
"vue/html-indent": "off",
"vue/require-default-prop": "off", // https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/require-default-prop.md
}
}

View File

@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

7367
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,41 +4,51 @@
"author": "Eduardo <eduardo.humberto1992@gmail.com>",
"private": true,
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --open --inline --hot",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
"dev": "cross-env NODE_ENV=development webpack --mode development --open --inline --hot",
"build": "cross-env NODE_ENV=production webpack --mode production --progress --hide-modules"
},
"dependencies": {
"axios": "^0.17.1",
"axios": "^0.18.0",
"buefy": "^0.6.3",
"bulma": "^0.6.2",
"fs": "0.0.1-security",
"html-to-json": "^0.6.0",
"mdi": "^2.1.99",
"moment": "^2.21.0",
"net": "^1.0.2",
"node-sass": "^4.7.2",
"qs": "^6.5.1",
"sass-loader": "^6.0.6",
"vue": "^2.5.13",
"tls": "0.0.1",
"vue": "^2.5.16",
"vue-router": "^3.0.1",
"vuedraggable": "^2.16.0",
"vuex": "^3.0.1"
},
"devDependencies": {
"autoprefixer": "^7.2.5",
"autoprefixer": "^8.2.0",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.1",
"babel-preset-es2015": "^6.0.0",
"babel-preset-stage-2": "^6.24.1",
"cross-env": "^3.0.0",
"css-loader": "^0.25.0",
"cross-env": "^5.1.4",
"css-loader": "^0.28.11",
"cypress": "^2.1.0",
"element-theme-chalk": "^2.1.0",
"file-loader": "^0.9.0",
"eslint": "^4.19.1",
"eslint-loader": "^2.0.0",
"eslint-plugin-vue": "^4.4.0",
"file-loader": "^1.1.11",
"postcss-loader": "^2.1.0",
"sass-resources-loader": "^1.3.2",
"style-loader": "^0.19.1",
"vue-custom-element": "^1.0.13",
"vue-loader": "^13.7.1",
"vue-template-compiler": "^2.5.13",
"webpack": "^3.10.0",
"webpack-dev-server": "^2.11.1"
"style-loader": "^0.20.3",
"uglifyjs-webpack-plugin": "^1.2.4",
"vue-custom-element": "^2.1.0",
"vue-loader": "^14.2.2",
"vue-template-compiler": "^2.5.16",
"webpack": "^4.3.0",
"webpack-cli": "^2.0.13",
"webpack-dev-server": "^3.1.1"
}
}

View File

@ -1,9 +1,11 @@
<template>
<div id="tainacan-admin-app" class="columns is-fullheight">
<primary-menu></primary-menu>
<tainacan-header></tainacan-header>
<div
id="tainacan-admin-app"
class="columns is-fullheight">
<primary-menu/>
<tainacan-header/>
<div class="column is-main-content">
<router-view></router-view>
<router-view/>
</div>
</div>
</template>

View File

@ -143,14 +143,16 @@ class Admin {
}
$settings = [
'root' => esc_url_raw( rest_url() ) . 'tainacan/v2',
'root_wp_api' => esc_url_raw( rest_url() ) . 'wp/v2/',
'nonce' => wp_create_nonce( 'wp_rest' ),
'components' => $components,
'i18n' => $tainacan_admin_i18n,
'user_caps' => $user_caps,
'user_prefs' => $prefs,
'base_url' => $TAINACAN_BASE_URL
'root' => esc_url_raw( rest_url() ) . 'tainacan/v2',
'root_wp_api' => esc_url_raw( rest_url() ) . 'wp/v2/',
'wp_ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'wp_rest' ),
'sample_permalink_nonce' => wp_create_nonce( 'samplepermalink' ),
'components' => $components,
'i18n' => $tainacan_admin_i18n,
'user_caps' => $user_caps,
'user_prefs' => $prefs,
'base_url' => $TAINACAN_BASE_URL
];
$maps = [

View File

@ -1,8 +1,14 @@
<template>
<div>
<div class="page-container primary-page">
<b-tag v-if="category != null && category != undefined" :type="'is-' + getStatusColor(category.status)" v-text="category.status"></b-tag>
<form v-if="category != null && category != undefined" class="tainacan-form" label-width="120px">
<b-tag
v-if="category != null && category != undefined"
:type="'is-' + getStatusColor(category.status)"
v-text="category.status"/>
<form
v-if="category != null && category != undefined"
class="tainacan-form"
label-width="120px">
<!-- Name -------------------------------- -->
<b-field
@ -12,14 +18,12 @@
:message="editFormErrors['name'] != undefined ? editFormErrors['name'] : ''">
<help-button
:title="$i18n.getHelperTitle('categories', 'name')"
:message="$i18n.getHelperMessage('categories', 'name')">
</help-button>
:message="$i18n.getHelperMessage('categories', 'name')"/>
<b-input
id="tainacan-text-name"
v-model="form.name"
@focus="clearErrors('name')"
@blur="updateSlug()">
</b-input>
@blur="updateSlug()"/>
</b-field>
<!-- Description -------------------------------- -->
@ -30,14 +34,12 @@
:message="editFormErrors['description'] != undefined ? editFormErrors['description'] : ''">
<help-button
:title="$i18n.getHelperTitle('categories', 'description')"
:message="$i18n.getHelperMessage('categories', 'description')">
</help-button>
:message="$i18n.getHelperMessage('categories', 'description')"/>
<b-input
id="tainacan-text-description"
type="textarea"
v-model="form.description"
@focus="clearErrors('description')">
</b-input>
@focus="clearErrors('description')"/>
</b-field>
<!-- Status -------------------------------- -->
@ -48,8 +50,7 @@
:message="editFormErrors['status'] != undefined ? editFormErrors['status'] : ''">
<help-button
:title="$i18n.getHelperTitle('categories', 'status')"
:message="$i18n.getHelperMessage('categories', 'status')">
</help-button>
:message="$i18n.getHelperMessage('categories', 'status')"/>
<b-select
id="tainacan-select-status"
v-model="form.status"
@ -72,14 +73,14 @@
:message="editFormErrors['slug'] != undefined ? editFormErrors['slug'] : ''">
<help-button
:title="$i18n.getHelperTitle('categories', 'slug')"
:message="$i18n.getHelperMessage('categories', 'slug')">
</help-button>
:message="$i18n.getHelperMessage('categories', '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-input>
:disabled="isUpdatingSlug"/>
</b-field>
<!-- Allow Insert -->
@ -88,8 +89,7 @@
:label="$i18n.get('label_category_allow_new_terms')">
<help-button
:title="$i18n.getHelperTitle('categories', 'allow_insert')"
:message="$i18n.getHelperMessage('categories', 'allow_insert')">
</help-button>
:message="$i18n.getHelperMessage('categories', 'allow_insert')"/>
<div class="block" >
<b-checkbox
v-model="form.allowInsert"
@ -100,6 +100,14 @@
</div>
</b-field>
<!-- Terms List -->
<b-field
:addons="false"
:label="$i18n.get('label_category_terms')">
<terms-list :category-id="categoryId"/>
</b-field>
<!-- Submit -->
<div class="field is-grouped form-submit">
<div class="control">
<button
@ -115,31 +123,37 @@
class="button is-success">{{ $i18n.get('save') }}</button>
</div>
</div>
<p class="help is-danger">{{formErrorMessage}}</p>
<p class="help is-danger">{{ formErrorMessage }}</p>
</form>
<b-loading :active.sync="isLoading" :canCancel="false"></b-loading>
<b-loading
:active.sync="isLoadingCategory"
:can-cancel="false"/>
</div>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import { wpAjax } from "../../js/mixins";
import { mapActions, mapGetters } from 'vuex';
import TermsList from '../lists/terms-list.vue'
import htmlToJSON from 'html-to-json';
export default {
name: 'CategoryEditionForm',
mixins: [ wpAjax ],
data(){
return {
categoryId: Number,
category: null,
isLoading: false,
isLoadingCategory: false,
isUpdatingSlug: false,
form: {
name: String,
status: String,
description: String,
slug: String,
allowInsert: String,
allowInsert: String
},
statusOptions: [{
value: 'publish',
@ -155,9 +169,12 @@
label: this.$i18n.get('trash')
}],
editFormErrors: {},
formErrorMessage: '',
formErrorMessage: ''
}
},
components: {
TermsList
},
methods: {
...mapActions('category', [
'createCategory',
@ -166,10 +183,11 @@
'fetchOnlySlug',
]),
...mapGetters('category',[
'getCategory'
'getCategory',
]),
onSubmit() {
this.isLoading = true;
this.isLoadingCategory = true;
let data = {
categoryId: this.categoryId,
@ -192,7 +210,7 @@
this.form.status = this.category.status;
this.allowInsert = this.category.allow_insert;
this.isLoading = false;
this.isLoadingCategory = false;
this.formErrorMessage = '';
this.editFormErrors = {};
@ -206,7 +224,7 @@
}
this.formErrorMessage = errors.error_message;
this.isLoading = false;
this.isLoadingCategory = false;
});
},
updateSlug(){
@ -216,43 +234,28 @@
this.isUpdatingSlug = true;
let data = {
categoryId: this.categoryId,
name: this.form.name,
description: this.form.description,
//slug: '',
status: 'private',
allowInsert: this.form.allowInsert
};
this.getSamplePermalink(this.categoryId, this.form.name, this.form.slug)
.then(samplePermalink => {
console.log(data);
let promise = htmlToJSON.parse(samplePermalink, {
permalink($doc) {
return $doc.find('#editable-post-name-full').text();
}
});
this.updateCategory(data)
.then(updatedCategory => {
this.category = updatedCategory;
console.info(this.category);
// Fill this.form data with current data.
this.form.name = this.category.name;
this.form.slug = this.category.slug;
this.form.description = this.category.description;
this.form.status = this.category.status;
this.allowInsert = this.category.allow_insert;
promise.done((result) => {
this.form.slug = result.permalink;
this.$console.info(this.form.slug);
});
this.isUpdatingSlug = false;
this.formErrorMessage = '';
this.editFormErrors = {};
})
.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.$console.error(errors);
this.isLoading = false;
this.isUpdatingSlug = false;
});
},
@ -272,7 +275,7 @@
},
createNewCategory() {
// Puts loading on Draft Category creation
this.isLoading = true;
this.isLoadingCategory = true;
// Creates draft Category
let data = {
@ -298,11 +301,10 @@
// Pre-fill status with publish to incentivate it
this.form.status = 'publish';
this.isLoading = false;
this.isLoadingCategory = false;
}
)
.catch(error => console.log(error));
})
.catch(error => this.$console.error(error));
},
clearErrors(attribute) {
this.editFormErrors[attribute] = undefined;
@ -312,7 +314,7 @@
},
labelNewTerms(){
return ( this.form.allowInsert === 'yes' ) ? this.$i18n.get('label_yes') : this.$i18n.get('label_no');
},
}
},
created(){
@ -320,7 +322,7 @@
this.createNewCategory();
} else if (this.$route.fullPath.split("/").pop() === "edit") {
this.isLoading = true;
this.isLoadingCategory = true;
// Obtains current category ID from URL
this.pathArray = this.$route.fullPath.split("/").reverse();
@ -336,11 +338,10 @@
this.form.status = this.category.status;
this.form.allowInsert = this.category.allow_insert;
this.isLoading = false;
this.isLoadingCategory = false;
});
}
}
}
</script>

View File

@ -1,7 +1,15 @@
<template>
<div class="page-container" :class="{'primary-page' : isNewCollection }">
<b-tag v-if="collection != null && collection != undefined" :type="'is-' + getStatusColor(collection.status)" v-text="collection.status"></b-tag>
<form v-if="collection != null && collection != undefined" class="tainacan-form" label-width="120px">
<div
class="page-container"
:class="{'primary-page' : isNewCollection }">
<b-tag
v-if="collection != null && collection != undefined"
:type="'is-' + getStatusColor(collection.status)"
v-text="collection.status"/>
<form
v-if="collection != null && collection != undefined"
class="tainacan-form"
label-width="120px">
<!-- Name -------------------------------- -->
<b-field
@ -11,13 +19,11 @@
:message="editFormErrors['name'] != undefined ? editFormErrors['name'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'name')"
:message="$i18n.getHelperMessage('collections', 'name')">
</help-button>
:message="$i18n.getHelperMessage('collections', 'name')"/>
<b-input
id="tainacan-text-name"
v-model="form.name"
@focus="clearErrors('name')">
</b-input>
@focus="clearErrors('name')"/>
</b-field>
<!-- Thumbnail -------------------------------- -->
@ -33,23 +39,29 @@
<div class="content has-text-centered">
<p>
<b-icon
icon="upload">
</b-icon>
icon="upload"/>
</p>
<p>{{ $i18n.get('instruction_image_upload_box') }}</p>
</div>
</b-upload>
<div v-else>
<figure class="image is-128x128">
<img :alt="$i18n.get('label_thumbnail')" :src="collection.featured_image"/>
<img
:alt="$i18n.get('label_thumbnail')"
:src="collection.featured_image">
</figure>
<div class="thumbnail-buttons-row">
<b-upload
model="thumbnail"
@input="uploadThumbnail($event)">
<a id="button-edit" :aria-label="$i18n.get('label_button_edit_thumb')"><b-icon icon="pencil"></b-icon></a>
model="thumbnail"
@input="uploadThumbnail($event)">
<a
id="button-edit"
:aria-label="$i18n.get('label_button_edit_thumb')"><b-icon icon="pencil"/></a>
</b-upload>
<a id="button-delete" :aria-label="$i18n.get('label_button_delete_thumb')" @click="deleteThumbnail()"><b-icon icon="delete"></b-icon></a>
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="deleteThumbnail()"><b-icon icon="delete"/></a>
</div>
</div>
</div>
@ -57,32 +69,29 @@
<!-- Description -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_description')"
:type="editFormErrors['description'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['description'] != undefined ? editFormErrors['description'] : ''">
:addons="false"
:label="$i18n.get('label_description')"
:type="editFormErrors['description'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['description'] != undefined ? editFormErrors['description'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'description')"
:message="$i18n.getHelperMessage('collections', 'description')">
</help-button>
:title="$i18n.getHelperTitle('collections', 'description')"
:message="$i18n.getHelperMessage('collections', 'description')"/>
<b-input
id="tainacan-text-description"
type="textarea"
v-model="form.description"
@focus="clearErrors('description')">
</b-input>
@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'] : ''">
:addons="false"
:label="$i18n.get('label_status')"
:type="editFormErrors['status'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['status'] != undefined ? editFormErrors['status'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'status')"
:message="$i18n.getHelperMessage('collections', 'status')">
</help-button>
:title="$i18n.getHelperTitle('collections', 'status')"
:message="$i18n.getHelperMessage('collections', 'status')"/>
<b-select
id="tainacan-select-status"
v-model="form.status"
@ -99,44 +108,44 @@
<!-- Slug -------------------------------- -->
<b-field
:addons="false"
:label="$i18n.get('label_slug')"
:type="editFormErrors['slug'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['slug'] != undefined ? editFormErrors['slug'] : ''">
:addons="false"
:label="$i18n.get('label_slug')"
:type="editFormErrors['slug'] != undefined ? 'is-danger' : ''"
:message="editFormErrors['slug'] != undefined ? editFormErrors['slug'] : ''">
<help-button
:title="$i18n.getHelperTitle('collections', 'slug')"
:message="$i18n.getHelperMessage('collections', 'slug')">
</help-button>
:title="$i18n.getHelperTitle('collections', 'slug')"
:message="$i18n.getHelperMessage('collections', 'slug')"/>
<b-input
id="tainacan-text-slug"
v-model="form.slug"
@focus="clearErrors('slug')">
</b-input>
id="tainacan-text-slug"
v-model="form.slug"
@focus="clearErrors('slug')"/>
</b-field>
<div class="field is-grouped form-submit">
<div class="control">
<button
id="button-cancel-collection-creation"
class="button is-outlined"
type="button"
@click="cancelBack">{{ $i18n.get('cancel') }}</button>
id="button-cancel-collection-creation"
class="button is-outlined"
type="button"
@click="cancelBack">{{ $i18n.get('cancel') }}</button>
</div>
<div class="control">
<button
id="button-submit-collection-creation"
@click.prevent="onSubmit"
class="button is-success">{{ $i18n.get('save') }}</button>
id="button-submit-collection-creation"
@click.prevent="onSubmit"
class="button is-success">{{ $i18n.get('save') }}</button>
</div>
</div>
<p class="help is-danger">{{formErrorMessage}}</p>
<p class="help is-danger">{{ formErrorMessage }}</p>
</form>
<b-loading :active.sync="isLoading" :canCancel="false"></b-loading>
<b-loading
:active.sync="isLoading"
:can-cancel="false"/>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import { mapActions } from 'vuex'
export default {
name: 'CollectionEditionForm',
@ -181,9 +190,6 @@ export default {
'sendAttachment',
'updateThumbnail'
]),
...mapGetters('collection',[
'getCollection'
]),
onSubmit() {
// Puts loading on Draft Collection creation
this.isLoading = true;
@ -251,7 +257,7 @@ export default {
this.isLoading = false;
})
.catch(error => console.log(error));
.catch(error => this.$console.error(error));
},
clearErrors(attribute) {
this.editFormErrors[attribute] = undefined;
@ -269,22 +275,22 @@ export default {
this.collection.featured_image = res.featured_image;
})
.catch((error) => {
console.log(error);
this.$console.error(error);
});
})
.catch((error) => {
console.log(error);
this.$console.error(error);
});
},
deleteThumbnail() {
this.updateThumbnail({collectionId: this.collectionId, thumbnailId: 0})
.then((res) => {
.then(() => {
this.collection.featured_image = false;
})
.catch((error) => {
console.log(error);
this.$console.error(error);
});
}
},

View File

@ -1,140 +1,152 @@
<template>
<form id="fieldEditForm" class="tainacan-form" v-on:submit.prevent="saveEdition(editForm)">
<form
id="fieldEditForm"
class="tainacan-form"
@submit.prevent="saveEdition(editForm)">
<b-field
:addons="false"
:type="formErrors['name'] != undefined ? 'is-danger' : ''"
:message="formErrors['name'] != undefined ? formErrors['name'] : ''">
:addons="false"
:type="formErrors['name'] != undefined ? 'is-danger' : ''"
:message="formErrors['name'] != undefined ? formErrors['name'] : ''">
<label class="label">
{{$i18n.get('label_name')}}
<span class="required-field-asterisk" :class="formErrors['name'] != undefined ? 'is-danger' : ''">*</span>
{{ $i18n.get('label_name') }}
<span
class="required-field-asterisk"
:class="formErrors['name'] != undefined ? 'is-danger' : ''">*</span>
<help-button
:title="$i18n.getHelperTitle('fields', 'name')"
:message="$i18n.getHelperMessage('fields', 'name')">
</help-button>
:title="$i18n.getHelperTitle('fields', 'name')"
:message="$i18n.getHelperMessage('fields', 'name')"/>
</label>
<b-input v-model="editForm.name" name="name" @focus="clearErrors('name')"></b-input>
<b-input
v-model="editForm.name"
name="name"
@focus="clearErrors('name')"/>
</b-field>
<b-field
:addons="false"
:type="formErrors['description'] != undefined ? 'is-danger' : ''"
:message="formErrors['description'] != undefined ? formErrors['description'] : ''">
:addons="false"
:type="formErrors['description'] != undefined ? 'is-danger' : ''"
:message="formErrors['description'] != undefined ? formErrors['description'] : ''">
<label class="label">
{{$i18n.get('label_description')}}
{{ $i18n.get('label_description') }}
<help-button
:title="$i18n.getHelperTitle('fields', 'description')"
:message="$i18n.getHelperMessage('fields', 'description')">
</help-button>
:title="$i18n.getHelperTitle('fields', 'description')"
:message="$i18n.getHelperMessage('fields', 'description')"/>
</label>
<b-input type="textarea" name="description" v-model="editForm.description" @focus="clearErrors('description')" ></b-input>
<b-input
type="textarea"
name="description"
v-model="editForm.description"
@focus="clearErrors('description')" />
</b-field>
<b-field
:addons="false"
:type="formErrors['status'] != undefined ? 'is-danger' : ''"
:message="formErrors['status'] != undefined ? formErrors['status'] : ''">
:addons="false"
:type="formErrors['status'] != undefined ? 'is-danger' : ''"
:message="formErrors['status'] != undefined ? formErrors['status'] : ''">
<label class="label">
{{$i18n.get('label_status')}}
{{ $i18n.get('label_status') }}
<help-button
:title="$i18n.getHelperTitle('fields', 'status')"
:message="$i18n.getHelperMessage('fields', 'status')">
</help-button>
:title="$i18n.getHelperTitle('fields', 'status')"
:message="$i18n.getHelperMessage('fields', 'status')"/>
</label>
<div class="inline-block">
<b-radio
@focus="clearErrors('label_status')"
id="tainacan-select-status-publish"
name="status"
v-model="editForm.status"
native-value="publish">
@focus="clearErrors('label_status')"
id="tainacan-select-status-publish"
name="status"
v-model="editForm.status"
native-value="publish">
{{ $i18n.get('publish_visibility') }}
</b-radio>
<br>
<b-radio
@focus="clearErrors('label_status')"
id="tainacan-select-status-private"
name="status"
v-model="editForm.status"
native-value="private">
@focus="clearErrors('label_status')"
id="tainacan-select-status-private"
name="status"
v-model="editForm.status"
native-value="private">
{{ $i18n.get('private_visibility') }}
</b-radio>
</div>
</b-field>
<br>
<b-field
:addons="false"
:label="$i18n.get('label_options')">
:addons="false"
:label="$i18n.get('label_options')">
<b-field
:type="formErrors['required'] != undefined ? 'is-danger' : ''"
:message="formErrors['required'] != undefined ? formErrors['required'] : ''">
:type="formErrors['required'] != undefined ? 'is-danger' : ''"
:message="formErrors['required'] != undefined ? formErrors['required'] : ''">
<b-checkbox
@input="clearErrors('required')"
v-model="editForm.required"
true-value="yes"
false-value="no"
name="required">
@input="clearErrors('required')"
v-model="editForm.required"
true-value="yes"
false-value="no"
name="required">
{{ $i18n.get('label_required') }}
</b-checkbox>
<help-button
:title="$i18n.getHelperTitle('fields', 'required')"
:message="$i18n.getHelperMessage('fields', 'required')">
</help-button>
:title="$i18n.getHelperTitle('fields', 'required')"
:message="$i18n.getHelperMessage('fields', 'required')"/>
</b-field>
<b-field
:type="formErrors['multiple'] != undefined ? 'is-danger' : ''"
:message="formErrors['multiple'] != undefined ? formErrors['multiple'] : ''">
:type="formErrors['multiple'] != undefined ? 'is-danger' : ''"
:message="formErrors['multiple'] != undefined ? formErrors['multiple'] : ''">
<b-checkbox
@input="clearErrors('multiple')"
v-model="editForm.multiple"
true-value="yes"
false-value="no"
name="multiple">
@input="clearErrors('multiple')"
v-model="editForm.multiple"
true-value="yes"
false-value="no"
name="multiple">
{{ $i18n.get('label_allow_multiple') }}
</b-checkbox>
<help-button
:title="$i18n.getHelperTitle('fields', 'multiple')"
:message="$i18n.getHelperMessage('fields', 'multiple')">
</help-button>
:title="$i18n.getHelperTitle('fields', 'multiple')"
:message="$i18n.getHelperMessage('fields', 'multiple')"/>
</b-field>
<b-field
:type="formErrors['unique'] != undefined ? 'is-danger' : ''"
:message="formErrors['unique'] != undefined ? formErrors['unique'] : ''">
:type="formErrors['unique'] != undefined ? 'is-danger' : ''"
:message="formErrors['unique'] != undefined ? formErrors['unique'] : ''">
<b-checkbox
@input="clearErrors('unique')"
v-model="editForm.unique"
true-value="yes"
false-value="no"
name="collecion_key">
@input="clearErrors('unique')"
v-model="editForm.unique"
true-value="yes"
false-value="no"
name="collecion_key">
{{ $i18n.get('label_unique_value') }}
</b-checkbox>
<help-button
:title="$i18n.getHelperTitle('fields', 'unique')"
:message="$i18n.getHelperMessage('fields', 'unique')">
</help-button>
:message="$i18n.getHelperMessage('fields', 'unique')"/>
</b-field>
</b-field>
<component
:errors="formErrors['field_type_options']"
v-if="(editForm.field_type_object && editForm.field_type_object.form_component) || editForm.edit_form == ''"
:is="editForm.field_type_object.form_component"
:field="editForm"
v-model="editForm.field_type_options">
</component>
<div v-html="editForm.edit_form" v-else></div>
:errors="formErrors['field_type_options']"
v-if="(editForm.field_type_object && editForm.field_type_object.form_component) || editForm.edit_form == ''"
:is="editForm.field_type_object.form_component"
:field="editForm"
v-model="editForm.field_type_options"/>
<div
v-html="editForm.edit_form"
v-else/>
<div class="field is-grouped form-submit">
<div class="control">
<button class="button is-outlined" @click.prevent="cancelEdition()" slot="trigger">{{ $i18n.get('cancel')}}</button>
<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('save')}}</button>
<button
class="button is-success"
type="submit">{{ $i18n.get('save') }}</button>
</div>
</div>
<p class="help is-danger">{{formErrorMessage}}</p>
<p class="help is-danger">{{ formErrorMessage }}</p>
</form>
</template>
@ -154,8 +166,8 @@ export default {
},
props: {
index: '',
editedField: {},
originalField: '',
editedField: Object,
originalField: Object,
isRepositoryLevel: false,
collectionId: ''
},
@ -188,7 +200,7 @@ export default {
if ((field.field_type_object && field.field_type_object.form_component) || field.edit_form == '') {
this.updateField({collectionId: this.collectionId, fieldId: field.id, isRepositoryLevel: this.isRepositoryLevel, index: this.index, options: this.editForm})
.then((field) => {
.then(() => {
this.editForm = {};
this.formErrors = {};
this.formErrorMessage = '';
@ -215,7 +227,7 @@ export default {
formObj[key] = value;
this.updateField({collectionId: this.collectionId, fieldId: field.id, isRepositoryLevel: this.isRepositoryLevel, index: this.index, options: formObj})
.then((field) => {
.then(() => {
this.editForm = {};
this.formErrors = {};
this.formErrorMessage = '';

View File

@ -1,85 +1,99 @@
<template>
<form id="filterEditForm" class="tainacan-form" v-on:submit.prevent="saveEdition(editForm)">
<form
id="filterEditForm"
class="tainacan-form"
@submit.prevent="saveEdition(editForm)">
<b-field
:addons="false"
:type="formErrors['name'] != undefined ? 'is-danger' : ''"
:message="formErrors['name'] != undefined ? formErrors['name'] : ''">
:addons="false"
:type="formErrors['name'] != undefined ? 'is-danger' : ''"
:message="formErrors['name'] != undefined ? formErrors['name'] : ''">
<label class="label">
{{$i18n.get('label_name')}}
<span class="required-field-asterisk" :class="formErrors['name'] != undefined ? 'is-danger' : ''">*</span>
{{ $i18n.get('label_name') }}
<span
class="required-field-asterisk"
:class="formErrors['name'] != undefined ? 'is-danger' : ''">*</span>
<help-button
:title="$i18n.getHelperTitle('filters', 'name')"
:message="$i18n.getHelperMessage('filters', 'name')">
</help-button>
:title="$i18n.getHelperTitle('filters', 'name')"
:message="$i18n.getHelperMessage('filters', 'name')"/>
</label>
<b-input v-model="editForm.name" name="name" @focus="clearErrors('name')"></b-input>
<b-input
v-model="editForm.name"
name="name"
@focus="clearErrors('name')"/>
</b-field>
<b-field
:addons="false"
:type="formErrors['description'] != undefined ? 'is-danger' : ''"
:message="formErrors['description'] != undefined ? formErrors['description'] : ''">
:addons="false"
:type="formErrors['description'] != undefined ? 'is-danger' : ''"
:message="formErrors['description'] != undefined ? formErrors['description'] : ''">
<label class="label">
{{$i18n.get('label_description')}}
{{ $i18n.get('label_description') }}
<help-button
:title="$i18n.getHelperTitle('filters', 'description')"
:message="$i18n.getHelperMessage('filters', 'description')">
</help-button>
:title="$i18n.getHelperTitle('filters', 'description')"
:message="$i18n.getHelperMessage('filters', 'description')"/>
</label>
<b-input type="textarea" name="description" v-model="editForm.description" @focus="clearErrors('description')" ></b-input>
<b-input
type="textarea"
name="description"
v-model="editForm.description"
@focus="clearErrors('description')" />
</b-field>
<b-field
:addons="false"
:type="formErrors['status'] != undefined ? 'is-danger' : ''"
:message="formErrors['status'] != undefined ? formErrors['status'] : ''">
:addons="false"
:type="formErrors['status'] != undefined ? 'is-danger' : ''"
:message="formErrors['status'] != undefined ? formErrors['status'] : ''">
<label class="label">
{{$i18n.get('label_status')}}
{{ $i18n.get('label_status') }}
<help-button
:title="$i18n.getHelperTitle('filters', 'status')"
:message="$i18n.getHelperMessage('filters', 'status')">
</help-button>
:title="$i18n.getHelperTitle('filters', 'status')"
:message="$i18n.getHelperMessage('filters', 'status')"/>
</label>
<div class="inline-block">
<b-radio
@focus="clearErrors('label_status')"
id="tainacan-select-status-publish"
name="status"
v-model="editForm.status"
native-value="publish">
@focus="clearErrors('label_status')"
id="tainacan-select-status-publish"
name="status"
v-model="editForm.status"
native-value="publish">
{{ $i18n.get('publish_visibility') }}
</b-radio>
<br>
<b-radio
@focus="clearErrors('label_status')"
id="tainacan-select-status-private"
name="status"
v-model="editForm.status"
native-value="private">
@focus="clearErrors('label_status')"
id="tainacan-select-status-private"
name="status"
v-model="editForm.status"
native-value="private">
{{ $i18n.get('private_visibility') }}
</b-radio>
</div>
</b-field>
<component
:errors="formErrors['filter_type_options']"
v-if="(editForm.filter_type_object && editForm.filter_type_object.form_component) || editForm.edit_form == ''"
:is="editForm.filter_type_object.form_component"
:filter="editForm"
v-model="editForm.filter_type_options">
</component>
<div v-html="editForm.edit_form" v-else></div>
:errors="formErrors['filter_type_options']"
v-if="(editForm.filter_type_object && editForm.filter_type_object.form_component) || editForm.edit_form == ''"
:is="editForm.filter_type_object.form_component"
:filter="editForm"
v-model="editForm.filter_type_options"/>
<div
v-html="editForm.edit_form"
v-else/>
<div class="field is-grouped form-submit">
<div class="control">
<button class="button is-outlined" @click.prevent="cancelEdition()" slot="trigger">{{ $i18n.get('cancel')}}</button>
<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('save')}}</button>
<button
class="button is-success"
type="submit">{{ $i18n.get('save') }}</button>
</div>
</div>
<p class="help is-danger">{{formErrorMessage}}</p>
<p class="help is-danger">{{ formErrorMessage }}</p>
</form>
</template>
@ -99,8 +113,8 @@ export default {
},
props: {
index: '',
editedFilter: {},
originalFilter: {},
editedFilter: Object,
originalFilter: Object,
},
created() {
@ -130,7 +144,7 @@ export default {
if ((filter.filter_type_object && filter.filter_type_object.form_component) || filter.edit_form == '') {
this.updateFilter({ filterId: filter.id, index: this.index, options: this.editForm})
.then((filter) => {
.then(() => {
this.editForm = {};
this.formErrors = {};
this.formErrorMessage = '';
@ -157,7 +171,7 @@ export default {
formObj[key] = value;
this.updateFilter({ filterId: filter.id, index: this.index, options: formObj})
.then((filter) => {
.then(() => {
this.editForm = {};
this.formErrors = {};
this.formErrorMessage = '';

View File

@ -1,14 +1,19 @@
<template>
<div class="page-container">
<b-tag v-if="!isLoading" :type="'is-' + getStatusColor(item.status)" v-text="item.status"></b-tag>
<form v-if="!isLoading" class="tainacan-form" label-width="120px">
<b-tag
v-if="!isLoading"
:type="'is-' + getStatusColor(item.status)"
v-text="item.status"/>
<form
v-if="!isLoading"
class="tainacan-form"
label-width="120px">
<b-field
:addons="false"
:label="$i18n.get('label_status')">
:addons="false"
:label="$i18n.get('label_status')">
<help-button
:title="$i18n.getHelperTitle('items', 'status')"
:message="$i18n.getHelperMessage('items', 'status')">
</help-button>
:title="$i18n.getHelperTitle('items', 'status')"
:message="$i18n.getHelperMessage('items', 'status')"/>
<b-select
id="status-select"
v-model="form.status"
@ -27,30 +32,36 @@
<b-field :label="$i18n.get('label_image')">
<div class="thumbnail-field">
<b-upload
v-if="item.featured_image == undefined || item.featured_image == false"
v-model="thumbnail"
drag-drop
@input="uploadThumbnail($event)">
v-if="item.featured_image == undefined || item.featured_image == false"
v-model="thumbnail"
drag-drop
@input="uploadThumbnail($event)">
<div class="content has-text-centered">
<p>
<b-icon
icon="upload">
</b-icon>
icon="upload"/>
</p>
<p>{{ $i18n.get('instruction_image_upload_box') }}</p>
</div>
</b-upload>
<div v-else>
<figure class="image is-128x128">
<img :alt="$i18n.get('label_thumbnail')" :src="item.featured_image"/>
<img
:alt="$i18n.get('label_thumbnail')"
:src="item.featured_image">
</figure>
<div class="thumbnail-buttons-row">
<b-upload
model="thumbnail"
@input="uploadThumbnail($event)">
<a id="button-edit" :aria-label="$i18n.get('label_button_edit_thumb')"><b-icon icon="pencil"></a>
model="thumbnail"
@input="uploadThumbnail($event)">
<a
id="button-edit"
:aria-label="$i18n.get('label_button_edit_thumb')"><b-icon icon="pencil"/></a>
</b-upload>
<a id="button-delete" :aria-label="$i18n.get('label_button_delete_thumb')" @click="deleteThumbnail()"><b-icon icon="delete"></a>
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete_thumb')"
@click="deleteThumbnail()"><b-icon icon="delete"/></a>
</div>
</div>
</div>
@ -59,14 +70,15 @@
<!-- Fields from Collection-------------------------------- -->
<tainacan-form-item
v-for="(field, index) in fieldList"
v-bind:key="index"
:field="field"></tainacan-form-item>
:key="index"
:field="field"/>
<!-- Attachments ------------------------------------------ -->
<div class="columns is-multiline">
<div class="column is-4">
<b-field :label="$i18n.get('label_image')">
<b-upload v-model="form.files"
<b-upload
v-model="form.files"
multiple
drag-drop
@input="uploadAttachment($event)">
@ -75,8 +87,7 @@
<p>
<b-icon
icon="upload"
size="is-large">
</b-icon>
size="is-large"/>
</p>
<p>{{ $i18n.get('instruction_image_upload_box') }}</p>
</div>
@ -84,48 +95,52 @@
</b-upload>
</b-field>
<div class="uploaded-files">
<div v-for="(file, index) in form.files"
:key="index">
<div
v-for="(file, index) in form.files"
:key="index">
<span class="tag is-primary">
{{ file.name }}
<button class="delete is-small"
<button
class="delete is-small"
type="button"
@click="deleteFile(index)">
</button>
@click="deleteFile(index)"/>
</span>
<!-- <progress class="progress is-secondary" value="15" max="100">30%</progress> -->
</div>
</div>
</div>
<div class="column is-narrow"
<div
class="column is-narrow"
v-for="(attachment, index) of item.attachments"
:key="index">
<figure class="image is-128x128">
<img
:alt="attachment.title"
:src="attachment.url"/>
:alt="attachment.title"
:src="attachment.url">
</figure>
</div>
</div>
<div class="field is-grouped form-submit">
<div class="control">
<button
id="button-cancel-item-creation"
class="button is-outlined"
type="button"
@click="cancelBack">{{ $i18n.get('cancel') }}</button>
id="button-cancel-item-creation"
class="button is-outlined"
type="button"
@click="cancelBack">{{ $i18n.get('cancel') }}</button>
</div>
<div class="control">
<button
id="button-submit-item-creation"
@click.prevent="onSubmit"
class="button is-success" :disabled="formHasErrors">{{ $i18n.get('save') }}</button>
id="button-submit-item-creation"
@click.prevent="onSubmit"
class="button is-success"
:disabled="formHasErrors">{{ $i18n.get('save') }}</button>
</div>
</div>
</form>
<b-loading :active.sync="isLoading" :canCancel="false">
</div>
<b-loading
:active.sync="isLoading"
:can-cancel="false"/></div>
</template>
<script>
@ -195,7 +210,7 @@ export default {
this.$router.push(this.$routerHelper.getItemPath(this.form.collectionId, this.itemId));
}).catch(error => {
this.$console.error(error);
this.isLoading = false;
});
},
@ -230,11 +245,11 @@ export default {
this.loadMetadata();
})
.catch(error => console.log(error));
.catch(error => this.$console.error(error));
},
loadMetadata() {
// Obtains Item Field
this.fetchFields(this.itemId).then(res => {
this.fetchFields(this.itemId).then(() => {
this.isLoading = false;
});
},
@ -245,11 +260,11 @@ export default {
for (let file of $event) {
this.sendAttachment({ item_id: this.itemId, file: file })
.then((res) => {
.then(() => {
})
.catch((error) => {
console.log(error);
this.$console.error(error);
});
}
},
@ -263,25 +278,25 @@ export default {
this.item.featured_image = res.featured_image;
})
.catch((error) => {
console.log(error);
this.$console.error(error);
});
})
.catch((error) => {
console.log(error);
this.$console.error(error);
});
},
deleteThumbnail() {
this.updateThumbnail({itemId: this.itemId, thumbnailId: 0})
.then((res) => {
.then(() => {
this.item.featured_image = false;
})
.catch((error) => {
console.log(error);
this.$console.error(error);
});
},
deleteFile(index) {
this.$console.log("Delete:" + index);
}
},
computed: {

View File

@ -0,0 +1,197 @@
<template>
<form
id="termEditForm"
class="tainacan-form"
@submit.prevent="saveEdition(editForm)">
<b-field
:addons="false"
:type="editForm.name == '' ? 'is-danger' : ''"
:message="editForm.name == '' ? $i18n.get('info_name_is_required') : ''">
<label class="label">
{{ $i18n.get('label_name') }}
<span
class="required-term-asterisk"
:class="editForm.name == '' ? 'is-danger' : ''">*</span>
<help-button
:title="$i18n.getHelperTitle('terms', 'name')"
:message="$i18n.getHelperMessage('terms', 'name')"/>
</label>
<b-input
v-model="editForm.name"
name="name"/>
</b-field>
<b-field :addons="false">
<label class="label">
{{ $i18n.get('label_description') }}
<help-button
:title="$i18n.getHelperTitle('terms', 'description')"
:message="$i18n.getHelperMessage('terms', 'description')"/>
</label>
<b-input
type="textarea"
name="description"
v-model="editForm.description"/>
</b-field>
<b-field :addons="false">
<label class="label">
{{ $i18n.get('label_parent_term') }}
<help-button
:title="$i18n.getHelperTitle('terms', 'parent_term')"
:message="$i18n.getHelperMessage('terms', 'parent_term')"/>
</label>
<b-select
id="parent_term_select"
v-model="editForm.parent"
:class="{'is-empty': editForm.parent == 0}"
:placeholder="$i18n.get('instruction_select_a_parent_term')">
<option
id="tainacan-select-parent-term"
v-for="(parentTerm, index) in parentTermsList"
:key="index"
:value="parentTerm.id">
{{ parentTerm.name }}
</option>
</b-select>
</b-field>
<div class="field is-grouped form-submit">
<div class="control">
<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"
:disabled="editForm.name == '' || editForm.name == undefined">
{{ $i18n.get('save') }}
</button>
</div>
</div>
</form>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
export default {
name: 'TermEditionForm',
data(){
return {
editForm: {},
oldForm: {},
closedByForm: false
}
},
props: {
index: '',
editedTerm: Object,
originalTerm: Object,
categoryId: ''
},
computed: {
parentTermsList() {
let parentTerms = [];
parentTerms.push({name: this.$i18n.get('label_no_parent_term'), id: 0});
for (let term of this.getTerms()) {
if (term.id != this.editForm.id)
parentTerms.push({id: term.id, name: term.name});
}
return parentTerms;
}
},
created() {
this.editForm = this.editedTerm;
this.oldForm = JSON.parse(JSON.stringify(this.originalTerm));
},
beforeDestroy() {
if (this.closedByForm) {
this.editedTerm.saved = true;
} else {
this.oldForm.saved = this.editForm.saved;
if (JSON.stringify(this.editForm) != JSON.stringify(this.oldForm))
this.editedTerm.saved = false;
else
this.editedTerm.saved = true;
}
},
methods: {
...mapActions('category', [
'sendTerm',
'updateTerm'
]),
...mapGetters('category', [
'getTerms'
]),
saveEdition(term) {
if (term.id == 'new') {
this.sendTerm({
categoryId: this.categoryId,
index: this.index,
name: this.editForm.name,
description: this.editForm.description,
parent: this.editForm.parent
})
.then(() => {
this.editForm = {};
this.closedByForm = true;
this.$emit('onEditionFinished');
})
.catch((error) => {
this.$emit('onErrorFound');
this.$console.log(error);
});
} else {
this.updateTerm({
categoryId: this.categoryId,
termId: term.id,
index: this.index,
name: this.editForm.name,
description: this.editForm.description,
parent: this.editForm.parent
})
.then(() => {
this.editForm = {};
this.closedByForm = true;
this.$emit('onEditionFinished');
})
.catch((error) => {
this.$emit('onErrorFound');
this.$console.log(error);
});
}
},
cancelEdition() {
this.closedByForm = true;
this.$emit('onEditionCanceled');
},
}
}
</script>
<style lang="scss" scoped>
@import "../../scss/_variables.scss";
form {
padding: 1.0em 2.0em;
border-top: 1px solid $draggable-border-color;
border-bottom: 1px solid $draggable-border-color;
margin-top: 1.0em;
}
</style>

View File

@ -1,12 +1,14 @@
<template>
<div>
<b-field grouped group-multiline>
<b-field
grouped
group-multiline>
<button
v-if="selectedCategories.length > 0"
class="button field is-danger"
@click="deleteSelectedCategories()">
<span>{{ $i18n.get('instruction_delete_selected_categories') }} </span>
<b-icon icon="delete"></b-icon>
<b-icon icon="delete"/>
</button>
</b-field>
@ -14,7 +16,6 @@
v-if="totalCategories > 0"
ref="categoryTable"
:data="categories"
@selection-change="handleSelectionChange"
:checked-rows.sync="selectedCategories"
checkable
:loading="isLoading"
@ -44,7 +45,10 @@
property="description"
show-overflow-tooltip
field="props.row.description">
<router-link class="clickable-row" tag="span" :to="{path: $routerHelper.getCategoryPath(props.row.id)}">
<router-link
class="clickable-row"
tag="span"
:to="{path: $routerHelper.getCategoryPath(props.row.id)}">
{{ props.row.description }}
</router-link>
</b-table-column>
@ -59,13 +63,17 @@
id="button-edit"
:aria-label="$i18n.getFrom('categories','edit_item')"
@click.prevent.stop="goToCategoryEditPage(props.row.id)">
<b-icon type="is-gray" icon="pencil" ></b-icon>
<b-icon
type="is-gray"
icon="pencil" />
</a>
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete')"
@click.prevent.stop="deleteOneCategory(props.row.id)">
<b-icon type="is-gray" icon="delete" ></b-icon>
<b-icon
type="is-gray"
icon="delete" />
</a>
</b-table-column>
</template>
@ -78,12 +86,13 @@
<p>
<b-icon
icon="inbox"
size="is-large">
</b-icon>
size="is-large"/>
</p>
<p>{{ $i18n.get('info_no_category_created') }}</p>
<router-link tag="button" class="button is-secondary"
:to="{ path: $routerHelper.getNewCategoryPath() }">
<router-link
tag="button"
class="button is-secondary"
:to="{ path: $routerHelper.getNewCategoryPath() }">
{{ $i18n.get('new') + ' ' + $i18n.get('category') }}
</router-link>
</div>
@ -93,7 +102,6 @@
</template>
<script>
import { mapActions } from 'vuex'
export default {
@ -103,7 +111,7 @@
totalCategories: 0,
page: 1,
categoriesPerPage: 12,
categories: []
categories: Array
},
data() {
return {
@ -118,28 +126,29 @@
this.$dialog.confirm({
message: this.$i18n.get('info_warning_category_delete'),
onConfirm: () => {
this.deleteCategory(categoryId).then(() => {
this.loadCategories();
this.$toast.open({
duration: 3000,
message: this.$i18n.get('info_category_deleted'),
position: 'is-bottom',
type: 'is-secondary',
queue: true
});
for (let i = 0; i < this.selectedCategories.length; i++) {
if (this.selectedCategories[i].id === this.categoryId)
this.selectedCategories.splice(i, 1);
}
}).catch(() =>
this.$toast.open({
duration: 3000,
message: this.$i18n.get('info_error_deleting_category'),
position: 'is-bottom',
type: 'is-danger',
queue: true
this.deleteCategory(categoryId)
.then(() => {
this.$toast.open({
duration: 3000,
message: this.$i18n.get('info_category_deleted'),
position: 'is-bottom',
type: 'is-secondary',
queue: true
});
for (let i = 0; i < this.selectedCategories.length; i++) {
if (this.selectedCategories[i].id === this.categoryId)
this.selectedCategories.splice(i, 1);
}
})
);
.catch(() => {
this.$toast.open({
duration: 3000,
message: this.$i18n.get('info_error_deleting_category'),
position: 'is-bottom',
type: 'is-danger',
queue: true
});
});
}
});
},
@ -150,7 +159,7 @@
for (let category of this.selectedCategories) {
this.deleteCategory(category.id)
.then((res) => {
.then(() => {
this.loadCategories();
this.$toast.open({
duration: 3000,
@ -159,7 +168,7 @@
type: 'is-secondary',
queue: false
})
}).catch((err) => {
}).catch(() => {
this.$toast.open({
duration: 3000,
message: this.$i18n.get('info_error_deleting_category'),
@ -173,8 +182,6 @@
}
});
},
handleSelectionChange(value) {
},
goToCategoryPage(categoryId) {
this.$router.push(this.$routerHelper.getCategoryPath(categoryId));
},

View File

@ -1,12 +1,16 @@
<template>
<div>
<b-field grouped group-multiline>
<button v-if="selectedCollections.length > 0" class="button field is-danger" @click="deleteSelectedCollections()"><span>{{$i18n.get('instruction_delete_selected_collections')}} </span><b-icon icon="delete"></b-icon></button>
<b-field
grouped
group-multiline>
<button
v-if="selectedCollections.length > 0"
class="button field is-danger"
@click="deleteSelectedCollections()"><span>{{ $i18n.get('instruction_delete_selected_collections') }} </span><b-icon icon="delete"/></button>
</b-field>
<b-table
ref="collectionTable"
:data="collections"
@selection-change="handleSelectionChange"
:checked-rows.sync="selectedCollections"
checkable
:loading="isLoading"
@ -16,33 +20,84 @@
backend-sorting>
<template slot-scope="props">
<b-table-column tabindex="0" :label="$i18n.get('label_thumbnail')" :aria-label="$i18n.get('label_thumbnail')" field="featured_image" width="55">
<template v-if="props.row.featured_image" slot-scope="scope">
<router-link tag="img" :to="{path: $routerHelper.getCollectionPath(props.row.id)}" class="table-thumb clickable-row" :src="`${props.row.featured_image}`"></router-link>
<b-table-column
tabindex="0"
:label="$i18n.get('label_thumbnail')"
:aria-label="$i18n.get('label_thumbnail')"
field="featured_image"
width="55">
<template
v-if="props.row.featured_image"
slot-scope="scope">
<router-link
tag="img"
:to="{path: $routerHelper.getCollectionPath(props.row.id)}"
class="table-thumb clickable-row"
:src="`${props.row.featured_image}`"/>
</template>
</b-table-column>
<b-table-column tabindex="0" :label="$i18n.get('label_name')" :aria-label="$i18n.get('label_name')" field="props.row.name">
<router-link class="clickable-row" tag="span" :to="{path: $routerHelper.getCollectionPath(props.row.id)}">
<b-table-column
tabindex="0"
:label="$i18n.get('label_name')"
:aria-label="$i18n.get('label_name')"
field="props.row.name">
<router-link
class="clickable-row"
tag="span"
:to="{path: $routerHelper.getCollectionPath(props.row.id)}">
{{ props.row.name }}
</router-link>
</b-table-column>
<b-table-column tabindex="0" :aria-label="$i18n.get('label_description')" :label="$i18n.get('label_description')" property="description" show-overflow-tooltip field="props.row.description">
<router-link class="clickable-row" tag="span" :to="{path: $routerHelper.getCollectionPath(props.row.id)}">
<b-table-column
tabindex="0"
:aria-label="$i18n.get('label_description')"
:label="$i18n.get('label_description')"
property="description"
show-overflow-tooltip
field="props.row.description">
<router-link
class="clickable-row"
tag="span"
:to="{path: $routerHelper.getCollectionPath(props.row.id)}">
{{ props.row.description }}
</router-link>
</b-table-column>
<b-table-column class="row-creation" tabindex="0" :aria-label="$i18n.get('label_creation') + ': ' + props.row.creation" :label="$i18n.get('label_creation')" property="creation" show-overflow-tooltip field="props.row.creation">
<router-link class="clickable-row" v-html="props.row.creation" tag="span" :to="{path: $routerHelper.getCollectionPath(props.row.id)}">
</router-link>
<b-table-column
class="row-creation"
tabindex="0"
:aria-label="$i18n.get('label_creation') + ': ' + props.row.creation"
:label="$i18n.get('label_creation')"
property="creation"
show-overflow-tooltip
field="props.row.creation">
<router-link
class="clickable-row"
v-html="props.row.creation"
tag="span"
:to="{path: $routerHelper.getCollectionPath(props.row.id)}"/>
</b-table-column>
<b-table-column tabindex="0" :label="$i18n.get('label_actions')" width="78" :aria-label="$i18n.get('label_actions')">
<b-table-column
tabindex="0"
:label="$i18n.get('label_actions')"
width="78"
:aria-label="$i18n.get('label_actions')">
<!-- <a id="button-view" :aria-label="$i18n.get('label_button_view')" @click.prevent.stop="goToCollectionPage(props.row.id)"><b-icon icon="eye"></a> -->
<a id="button-edit" :aria-label="$i18n.getFrom('collections','edit_item')" @click.prevent.stop="goToCollectionEditPage(props.row.id)"><b-icon type="is-gray" icon="pencil"></a>
<a id="button-delete" :aria-label="$i18n.get('label_button_delete')" @click.prevent.stop="deleteOneCollection(props.row.id)"><b-icon type="is-gray" icon="delete"></a>
<a
id="button-edit"
:aria-label="$i18n.getFrom('collections','edit_item')"
@click.prevent.stop="goToCollectionEditPage(props.row.id)"><b-icon
type="is-gray"
icon="pencil"/></a>
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete')"
@click.prevent.stop="deleteOneCollection(props.row.id)"><b-icon
type="is-gray"
icon="delete"/></a>
</b-table-column>
</template>
@ -53,12 +108,13 @@
<p>
<b-icon
icon="inbox"
size="is-large">
</b-icon>
size="is-large"/>
</p>
<p>{{$i18n.get('info_no_collection_created')}}</p>
<router-link tag="button" class="button is-primary"
:to="{ path: $routerHelper.getNewCollectionPath() }">
<p>{{ $i18n.get('info_no_collection_created') }}</p>
<router-link
tag="button"
class="button is-primary"
:to="{ path: $routerHelper.getNewCollectionPath() }">
{{ $i18n.getFrom('collections', 'new_item') }}
</router-link>
</div>
@ -70,7 +126,7 @@
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
import { mapActions } from 'vuex'
export default {
name: 'CollectionsList',
@ -84,7 +140,7 @@ export default {
totalCollections: 0,
page: 1,
collectionsPerPage: 12,
collections: []
collections: Array
},
methods: {
...mapActions('collection', [
@ -95,7 +151,6 @@ export default {
message: this.$i18n.get('info_warning_collection_delete'),
onConfirm: () => {
this.deleteCollection(collectionId).then(() => {
this.loadCollections();
this.$toast.open({
duration: 3000,
message: this.$i18n.get('info_collection_deleted'),
@ -126,7 +181,7 @@ export default {
for (let collection of this.selectedCollections) {
this.deleteCollection(collection.id)
.then((res) => {
.then(() => {
this.loadCollections();
this.$toast.open({
duration: 3000,
@ -135,7 +190,7 @@ export default {
type: 'is-secondary',
queue: false
})
}).catch((err) => {
}).catch(() => {
this.$toast.open({
duration: 3000,
message: this.$i18n.get('info_error_deleting_collection'),
@ -149,8 +204,6 @@ export default {
}
});
},
handleSelectionChange(value) {
},
goToCollectionPage(collectionId) {
this.$router.push(this.$routerHelper.getCollectionPath(collectionId));
},

View File

@ -1,77 +1,94 @@
<template>
<div>
<b-loading :active.sync="isLoadingFieldTypes"></b-loading>
<b-loading :active.sync="isLoadingFieldTypes"/>
<div class="page-title">
<h2>{{ isRepositoryLevel ? $i18n.get('instruction_dragndrop_fields_repository') : $i18n.get('instruction_dragndrop_fields_collection')}}</h2>
<h2>{{ isRepositoryLevel ? $i18n.get('instruction_dragndrop_fields_repository') : $i18n.get('instruction_dragndrop_fields_collection') }}</h2>
</div>
<div class="columns">
<div class="column">
<draggable
class="active-fields-area"
@change="handleChange"
:class="{'fields-area-receive': isDraggingFromAvailable}"
:list="activeFieldList"
:options="{
group: { name:'fields', pull: false, put: true },
sort: openedFieldId == '' || openedFieldId == undefined,
disabled: openedFieldId != '' && openedFieldId != undefined,
handle: '.handle',
ghostClass: 'sortable-ghost',
filter: 'not-sortable-item',
animation: '250'}">
class="active-fields-area"
@change="handleChange"
:class="{'fields-area-receive': isDraggingFromAvailable}"
:list="activeFieldList"
:options="{
group: { name:'fields', pull: false, put: true },
sort: openedFieldId == '' || openedFieldId == undefined,
disabled: openedFieldId != '' && openedFieldId != undefined,
handle: '.handle',
ghostClass: 'sortable-ghost',
filter: 'not-sortable-item',
animation: '250'}">
<div
class="active-field-item"
:class="{
'not-sortable-item': field.id == undefined || openedFieldId != '' ,
'not-focusable-item': openedFieldId == field.id,
'disabled-field': field.enabled == false}"
v-for="(field, index) in activeFieldList" :key="index">
class="active-field-item"
:class="{
'not-sortable-item': field.id == undefined || openedFieldId != '' ,
'not-focusable-item': openedFieldId == field.id,
'disabled-field': field.enabled == false
}"
v-for="(field, index) in activeFieldList"
:key="index">
<div class="handle">
<grip-icon></grip-icon>
<grip-icon/>
<span
class="field-name"
:class="{'is-danger': formWithErrors == field.id }">
{{ field.name }}
class="field-name"
:class="{'is-danger': formWithErrors == field.id }">
{{ field.name }}
</span>
<span
v-if="field.id != undefined"
class="label-details">
({{ $i18n.get(field.field_type_object.component) }})
<span class="not-saved" v-if="(editForms[field.id] != undefined && editForms[field.id].saved != true) || field.status == 'auto-draft'">
v-if="field.id != undefined"
class="label-details">
({{ $i18n.get(field.field_type_object.component) }})
<span
class="not-saved"
v-if="(editForms[field.id] != undefined && editForms[field.id].saved != true) || field.status == 'auto-draft'">
{{ $i18n.get('info_not_saved') }}
</span>
</span>
<span class="loading-spinner" v-if="field.id == undefined"></span>
<span class="controls" v-if="field.id !== undefined">
<b-switch size="is-small" v-model="field.enabled" @input="onChangeEnable($event, index)"></b-switch>
<a :style="{ visibility:
<span
class="loading-spinner"
v-if="field.id == undefined"/>
<span
class="controls"
v-if="field.id !== undefined">
<b-switch
size="is-small"
v-model="field.enabled"
@input="onChangeEnable($event, index)"/>
<a
:style="{ visibility:
field.collection_id != collectionId
? 'hidden' : 'visible'
}"
@click.prevent="editField(field)">
<b-icon type="is-gray" icon="pencil"></b-icon>
@click.prevent="editField(field)">
<b-icon
type="is-gray"
icon="pencil"/>
</a>
<a :style="{ visibility:
<a
:style="{ visibility:
field.collection_id != collectionId ||
field.field_type == 'Tainacan\\Field_Types\\Core_Title' ||
field.field_type == 'Tainacan\\Field_Types\\Core_Description'
? 'hidden' : 'visible'
}"
@click.prevent="removeField(field)">
<b-icon type="is-gray" icon="delete"></b-icon>
@click.prevent="removeField(field)">
<b-icon
type="is-gray"
icon="delete"/>
</a>
</span>
</div>
<div v-if="openedFieldId == field.id">
<field-edition-form
:collectionId="collectionId"
:isRepositoryLevel="isRepositoryLevel"
@onEditionFinished="onEditionFinished()"
@onEditionCanceled="onEditionCanceled()"
@onErrorFound="formWithErrors = field.id"
:index="index"
:originalField="field"
:editedField="editForms[field.id]"></field-edition-form>
:collection-id="collectionId"
:is-repository-level="isRepositoryLevel"
@onEditionFinished="onEditionFinished()"
@onEditionCanceled="onEditionCanceled()"
@onErrorFound="formWithErrors = field.id"
:index="index"
:original-field="field"
:edited-field="editForms[field.id]"/>
</div>
</div>
</draggable>
@ -79,23 +96,25 @@
<div class="column available-fields-area" >
<div class="field">
<h3 class="label">{{ $i18n.get('label_available_field_types')}}</h3>
<h3 class="label">{{ $i18n.get('label_available_field_types') }}</h3>
<draggable
:list="availableFieldList"
:options="{
sort: false,
group: { name:'fields', pull: 'clone', put: false, revertClone: true },
dragClass: 'sortable-drag'
}">
:list="availableFieldList"
:options="{
sort: false,
group: { name:'fields', pull: 'clone', put: false, revertClone: true },
dragClass: 'sortable-drag'
}">
<div
@click.prevent="addFieldViaButton(field)"
class="available-field-item"
:class="{ 'hightlighted-field' : hightlightedField == field.name }"
v-for="(field, index) in availableFieldList"
:key="index">
<grip-icon></grip-icon>
@click.prevent="addFieldViaButton(field)"
class="available-field-item"
:class="{ 'hightlighted-field' : hightlightedField == field.name }"
v-for="(field, index) in availableFieldList"
:key="index">
<grip-icon/>
<span class="field-name">{{ field.name }}</span>
<span class="loading-spinner" v-if="hightlightedField == field.name"></span>
<span
class="loading-spinner"
v-if="hightlightedField == field.name"/>
</div>
</draggable>
</div>
@ -207,7 +226,7 @@ export default {
this.hightlightedField = '';
})
.catch((error) => {
console.log(error);
this.$console.error(error);
});
},
removeField(removedField) {
@ -220,7 +239,7 @@ export default {
if (!this.isRepositoryLevel)
this.updateFieldsOrder();
})
.catch((error) => {
.catch(() => {
});
},
editField(field) {
@ -255,7 +274,6 @@ export default {
delete this.editForms[this.openedFieldId];
this.openedFieldId = '';
}
},
computed: {
availableFieldList() {
@ -270,10 +288,10 @@ export default {
this.isLoadingFields = true;
this.fetchFieldTypes()
.then((res) => {
.then(() => {
this.isLoadingFieldTypes = false;
})
.catch((error) => {
.catch(() => {
this.isLoadingFieldTypes = false;
});
@ -285,10 +303,10 @@ export default {
this.fetchFields({collectionId: this.collectionId, isRepositoryLevel: this.isRepositoryLevel})
.then((res) => {
.then(() => {
this.isLoadingFields = false;
})
.catch((error) => {
.catch(() => {
this.isLoadingFields = false;
});
}

View File

@ -3,13 +3,12 @@
<tainacan-filters-list
:query="getPostQuery()"
v-for="(filter, index) in filters"
v-bind:key="index"
:filter="filter"></tainacan-filters-list>
:key="index"
:filter="filter"/>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
import { eventFilterBus } from '../../../js/event-bus-filters'
export default {
data(){

View File

@ -1,120 +1,136 @@
<template>
<div>
<b-loading :active.sync="isLoadingFieldTypes"></b-loading>
<b-loading :active.sync="isLoadingFieldTypes"/>
<div class="page-title">
<h2>{{ isRepositoryLevel ? $i18n.get('instruction_dragndrop_filters_collection') : $i18n.get('instruction_dragndrop_filters_collection') }}</h2>
</div>
<div class="columns">
<div class="column">
<draggable
class="active-filters-area"
@change="handleChange"
:class="{'filters-area-receive': isDraggingFromAvailable}"
:list="activeFilterList"
:options="{
group: { name:'filters', pull: false, put: true },
sort: openedFilterId == '' || openedFilterId == undefined,
disabled: openedFilterId != '' && openedFilterId != undefined,
handle: '.handle',
ghostClass: 'sortable-ghost',
filter: 'not-sortable-item',
animation: '250'}">
class="active-filters-area"
@change="handleChange"
:class="{'filters-area-receive': isDraggingFromAvailable}"
:list="activeFilterList"
:options="{
group: { name:'filters', pull: false, put: true },
sort: openedFilterId == '' || openedFilterId == undefined,
disabled: openedFilterId != '' && openedFilterId != undefined,
handle: '.handle',
ghostClass: 'sortable-ghost',
filter: 'not-sortable-item',
animation: '250'}">
<div
class="active-filter-item"
:class="{
'not-sortable-item': filter.id == undefined || openedFilterId != '' || choosenField.name == filter.name,
'not-focusable-item': openedFilterId == filter.id,
'disabled-filter': filter.enabled == false
}"
v-for="(filter, index) in activeFilterList" :key="index">
<div class="handle">
<grip-icon></grip-icon>
<span
class="active-filter-item"
:class="{
'not-sortable-item': filter.id == undefined || openedFilterId != '' || choosenField.name == filter.name,
'not-focusable-item': openedFilterId == filter.id,
'disabled-filter': filter.enabled == false
}"
v-for="(filter, index) in activeFilterList"
:key="index">
<div class="handle">
<grip-icon/>
<span
class="filter-name"
:class="{'is-danger': formWithErrors == filter.id }">
{{ filter.name }}
</span>
<span
v-if="filter.filter_type_object != undefined"
class="label-details">
({{ $i18n.get(filter.filter_type_object.component) }})
<span class="not-saved" v-if="(editForms[filter.id] != undefined && editForms[filter.id].saved != true) ||filter.status == 'auto-draft'">
</span>
<span
v-if="filter.filter_type_object != undefined"
class="label-details">
({{ $i18n.get(filter.filter_type_object.component) }})
<span
class="not-saved"
v-if="(editForms[filter.id] != undefined && editForms[filter.id].saved != true) ||filter.status == 'auto-draft'">
{{ $i18n.get('info_not_saved') }}
</span>
</span>
<span class="loading-spinner" v-if="filter.id == undefined"></span>
<span class="controls" v-if="filter.filter_type != undefined">
<b-switch size="is-small" v-model="filter.enabled" @input="onChangeEnable($event, index)"></b-switch>
<a :style="{ visibility: filter.collection_id != collectionId ? 'hidden' : 'visible' }"
</span>
</span>
<span
class="loading-spinner"
v-if="filter.id == undefined"/>
<span
class="controls"
v-if="filter.filter_type != undefined">
<b-switch
size="is-small"
v-model="filter.enabled"
@input="onChangeEnable($event, index)"/>
<a
:style="{ visibility: filter.collection_id != collectionId ? 'hidden' : 'visible' }"
@click.prevent="editFilter(filter)">
<b-icon type="is-gray" icon="pencil"></b-icon>
</a>
<a :style="{ visibility: filter.collection_id != collectionId ? 'hidden' : 'visible' }"
<b-icon
type="is-gray"
icon="pencil"/>
</a>
<a
:style="{ visibility: filter.collection_id != collectionId ? 'hidden' : 'visible' }"
@click.prevent="removeFilter(filter)">
<b-icon type="is-gray" icon="delete"></b-icon>
</a>
</span>
</div>
<div v-if="choosenField.name == filter.name && openedFilterId == ''">
<form class="tainacan-form">
<b-field :label="$i18n.get('label_filter_type')">
<b-select
v-model="selectedFilterType"
:placeholder="$i18n.get('instruction_select_a_filter_type')">
<option
<b-icon
type="is-gray"
icon="delete"/>
</a>
</span>
</div>
<div v-if="choosenField.name == filter.name && openedFilterId == ''">
<form class="tainacan-form">
<b-field :label="$i18n.get('label_filter_type')">
<b-select
v-model="selectedFilterType"
:placeholder="$i18n.get('instruction_select_a_filter_type')">
<option
v-for="(filterType, index) in allowedFilterTypes"
:key="index"
:selected="index == 0"
:value="filterType">
{{ filterType.name }}</option>
</b-select>
</b-field>
<div class="field is-grouped form-submit">
<div class="control">
<button
</b-select>
</b-field>
<div class="field is-grouped form-submit">
<div class="control">
<button
class="button is-outlined"
@click.prevent="cancelFilterTypeSelection()"
slot="trigger">{{ $i18n.get('cancel')}}</button>
</div>
<div class="control">
<button
slot="trigger">{{ $i18n.get('cancel') }}</button>
</div>
<div class="control">
<button
class="button is-success"
type="submit"
:disabled="Object.keys(selectedFilterType).length == 0"
@click.prevent="confirmSelectedFilterType()">{{ $i18n.get('next')}}</button>
</div>
@click.prevent="confirmSelectedFilterType()">{{ $i18n.get('next') }}</button>
</div>
</form>
</div>
<b-field v-if="openedFilterId == filter.id">
<filter-edition-form
</div>
</form>
</div>
<b-field v-if="openedFilterId == filter.id">
<filter-edition-form
@onEditionFinished="onEditionFinished()"
@onEditionCanceled="onEditionCanceled()"
@onErrorFound="formWithErrors = filter.id"
:index="index"
:originalFilter="filter"
:editedFilter="editForms[openedFilterId]"></filter-edition-form>
</b-field>
</div>
:original-filter="filter"
:edited-filter="editForms[openedFilterId]"/>
</b-field>
</div>
</draggable>
</div>
<div class="column available-fields-area">
<div class="field">
<h3 class="label"> {{ $i18n.get('label_available_field_types') }}</h3>
<draggable
:list="availableFieldList"
:options="{
sort: false,
group: { name:'filters', pull: true, put: false, revertClone: true },
dragClass: 'sortable-drag'
}">
:list="availableFieldList"
:options="{
sort: false,
group: { name:'filters', pull: true, put: false, revertClone: true },
dragClass: 'sortable-drag'
}">
<div
class="available-field-item"
v-for="(field, index) in availableFieldList"
:key="index"
@click.prevent="addFieldViaButton(field, index)">
<grip-icon></grip-icon>
class="available-field-item"
v-for="(field, index) in availableFieldList"
:key="index"
@click.prevent="addFieldViaButton(field, index)">
<grip-icon/>
<span class="field-name">{{ field.name }}</span>
</div>
</draggable>
@ -226,7 +242,7 @@ export default {
this.addNewFilter(fieldType, lastIndex);
},
addNewFilter(choosenField, newIndex) {
console.log(choosenField);
this.$console.log(choosenField);
this.choosenField = choosenField;
this.newIndex = newIndex;
this.openedFilterId = '';
@ -264,7 +280,7 @@ export default {
this.editFilter(filter);
})
.catch((error) => {
console.log(error);
this.$console.error(error);
this.newIndex = 0;
this.choosenField = {};
this.selectedFilterType = {}
@ -280,17 +296,15 @@ export default {
this.activeFilterList.splice(index, 1);
this.isLoadingFieldTypes = true;
this.fetchFields({collectionId: this.collectionId, isRepositoryLevel: this.isRepositoryLevel})
.then((res) => {
.then(() => {
this.isLoadingFieldTypes = false;
})
.catch((error) => {
.catch(() => {
this.isLoadingFieldTypes = false;
});
if (!this.isRepositoryLevel)
this.updateFiltersOrder();
})
.catch((error) => {
});
},
confirmSelectedFilterType() {
@ -311,7 +325,7 @@ export default {
// Opening collapse
} else {
console.log(this.choosenField);
this.$console.log(this.choosenField);
if (this.openedFilterId == '' && this.choosenField.id != undefined) {
this.availableFieldList.push(this.choosenField);
this.choosenField = {};
@ -379,26 +393,26 @@ export default {
this.isLoadingFilterTypes = true;
this.fetchFilterTypes()
.then((res) => {
.then(() => {
this.isLoadingFilterTypes = false;
})
.catch((error) => {
.catch(() => {
this.isLoadingFilterTypes = false;
});
this.fetchFilters({collectionId: this.collectionId, isRepositoryLevel: this.isRepositoryLevel})
.then((res) => {
.then(() => {
this.isLoadingFilters = false;
// Needs to be done after activeFilterList exists to compare and remove chosen fields.
this.fetchFields({collectionId: this.collectionId, isRepositoryLevel: this.isRepositoryLevel})
.then((res) => {
.then(() => {
this.isLoadingFieldTypes = false;
})
.catch((error) => {
.catch(() => {
this.isLoadingFieldTypes = false;
});
})
.catch((error) => {
.catch(() => {
this.isLoadingFilters = false;
});
}

View File

@ -1,7 +1,14 @@
<template>
<div>
<b-field grouped group-multiline>
<button v-if="selectedItems.length > 0" class="button field is-danger" @click="deleteSelectedItems()"><span>{{$i18n.get('instruction_delete_selected_items')}} </span><b-icon icon="delete"></b-icon></button>
<b-field
grouped
group-multiline>
<button
v-if="selectedItems.length > 0"
class="button field is-danger"
@click="deleteSelectedItems()">
<span>{{ $i18n.get('instruction_delete_selected_items') }} </span><b-icon icon="delete"/>
</button>
</b-field>
<b-table
ref="itemsTable"
@ -15,27 +22,44 @@
selectable
backend-sorting>
<template slot-scope="props">
<b-table-column v-for="(column, index) in tableFields"
:key="index"
:label="column.label"
:visible="column.visible"
:width="column.field == 'row_actions' ? 78 : column.field == 'featured_image' ? 55 : undefined ">
<router-link tag="span" class="clickable-row" :to="{path: $routerHelper.getItemPath(collectionId, props.row.id)}">
<b-table-column
v-for="(column, index) in tableFields"
:key="index"
:label="column.label"
:visible="column.visible"
:width="column.field == 'row_actions' ? 78 : column.field == 'featured_image' ? 55 : undefined ">
<router-link
tag="span"
class="clickable-row"
:to="{path: $routerHelper.getItemPath(collectionId, props.row.id)}">
<template v-if="column.field != 'featured_image' && column.field != 'row_actions'">
{{ showValue( props.row.metadata[column.slug] ) }}
{{ showValue( props.row.metadata[column.slug] ) }}
</template>
</router-link>
<template v-if="column.field == 'featured_image'">
<router-link tag="img" class="table-thumb clickable-row" :to="{path: $routerHelper.getItemPath(collectionId, props.row.id)}" :src="props.row[column.slug]"></router-link>
<router-link
tag="img"
class="table-thumb clickable-row"
:to="{path: $routerHelper.getItemPath(collectionId, props.row.id)}"
:src="props.row[column.slug]"/>
</template>
<template v-if="column.field == 'row_actions'">
<!-- <a id="button-view" @click.prevent.stop="goToItemPage(props.row.id)"><b-icon icon="eye"></a> -->
<a id="button-edit" :aria-label="$i18n.getFrom('items','edit_item')" @click="goToItemEditPage(props.row.id)"><b-icon type="is-gray" icon="pencil"></a>
<a id="button-delete" :aria-label="$i18n.get('label_button_delete')" @click="deleteOneItem(props.row.id)"><b-icon type="is-gray" icon="delete"></a>
<a
id="button-edit"
:aria-label="$i18n.getFrom('items','edit_item')"
@click="goToItemEditPage(props.row.id)"><b-icon
type="is-gray"
icon="pencil"/></a>
<a
id="button-delete"
:aria-label="$i18n.get('label_button_delete')"
@click="deleteOneItem(props.row.id)"><b-icon
type="is-gray"
icon="delete"/></a>
</template>
</b-table-column>
@ -46,15 +70,15 @@
<div class="content has-text-grey has-text-centered">
<p>
<b-icon
icon="inbox"
size="is-large">
</b-icon>
icon="inbox"
size="is-large"/>
</p>
<p>{{$i18n.get('info_no_item_created')}}</p>
<p>{{ $i18n.get('info_no_item_created') }}</p>
<router-link
id="button-create"
tag="button" class="button is-primary"
:to="{ path: $routerHelper.getNewItemPath(collectionId) }">
id="button-create"
tag="button"
class="button is-primary"
:to="{ path: $routerHelper.getNewItemPath(collectionId) }">
{{ $i18n.getFrom('items', 'new_item') }}
</router-link>
</div>
@ -65,7 +89,7 @@
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
import { mapActions } from 'vuex';
export default {
name: 'ItemsList',
@ -76,12 +100,12 @@ export default {
},
props: {
collectionId: Number,
tableFields: [],
prefTableFields: [],
tableFields: Array,
prefTableFields: Array,
totalItems: 0,
page: 1,
itemsPerPage: 12,
items: [],
items: Array,
isLoading: false
},
methods: {
@ -92,7 +116,7 @@ export default {
this.$dialog.confirm({
message: this.$i18n.get('info_warning_item_delete'),
onConfirm: () => {
this.deleteItem(itemId).then((res) => {
this.deleteItem(itemId).then(() => {
this.loadItems();
this.$toast.open({
duration: 3000,
@ -105,7 +129,7 @@ export default {
if (this.selectedItems[i].id == this.itemId)
this.selectedItems.splice(i, 1);
}
}).catch(( error ) => {
}).catch(() => {
this.$toast.open({
duration: 3000,
@ -125,7 +149,7 @@ export default {
for (let item of this.selectedItems) {
this.deleteItem(item.id)
.then((res) => {
.then(() => {
this.loadItems();
this.$toast.open({
duration: 3000,
@ -135,7 +159,7 @@ export default {
queue: false
});
}).catch((err) => {
}).catch(() => {
this.$toast.open({
duration: 3000,
message: this.$i18n.get('info_error_deleting_item'),

View File

@ -0,0 +1,333 @@
<template>
<div>
<button
class="button is-secondary is-small"
type="button"
@click="addNewTerm()">
{{ $i18n.get('label_new_term') }}
</button>
<div
class="term-item"
:class="{
'not-sortable-item': term.id == 'new' || term.id == undefined || openedTermId != '' ,
'not-focusable-item': openedTermId == term.id
}"
:style="{'margin-left': (term.depth * 20) + 'px'}"
v-for="(term, index) in orderedTermsList"
:key="index">
<span
class="term-name"
:class="{'is-danger': formWithErrors == term.id }">
{{ term.name }}
</span>
<span
v-if="term.id != undefined"
class="label-details">
<span
class="not-saved"
v-if="(editForms[term.id] != undefined && editForms[term.id].saved != true) || term.id == 'new'">
{{ $i18n.get('info_not_saved') }}
</span>
</span>
<span
class="loading-spinner"
v-if="term.id == undefined"/>
<span class="controls" >
<a @click.prevent="editTerm(term)">
<b-icon
type="is-gray"
icon="pencil"/>
</a>
<a
@click.prevent="removeTerm(term)">
<b-icon
type="is-gray"
icon="delete"/>
</a>
</span>
<div v-if="openedTermId == term.id">
<term-edition-form
:category-id="categoryId"
@onEditionFinished="onTermEditionFinished()"
@onEditionCanceled="onTermEditionCanceled()"
@onErrorFound="formWithErrors = term.id"
:index="index"
:original-term="term"
:edited-term="editForms[term.id]"/>
</div>
</div>
<b-loading
:active.sync="isLoadingTerms"
:can-cancel="false"/>
</div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex';
import TermEditionForm from '../edition/term-edition-form.vue'
export default {
name: 'TermsList',
data(){
return {
// Terms related
isLoadingTerms: false,
formWithErrors: '',
openedTermId: '',
editForms: [],
orderedTermsList: []
}
},
props: {
categoryId: String
},
computed: {
termsList() {
return this.getTerms();
}
},
watch: {
'termsList'() {
this.generateOrderedTerms();
}
},
components: {
TermEditionForm
},
beforeRouteUpdate ( to, from, next ) {
let hasUnsavedForms = false;
for (let editForm in this.editForms) {
if (!this.editForms[editForm].saved)
hasUnsavedForms = true;
}
if ((this.openedTermId != '' && this.openedTermId != undefined) || hasUnsavedForms ) {
this.$dialog.confirm({
message: this.$i18n.get('info_warning_terms_not_saved'),
onConfirm: () => {
this.onEditionCanceled();
next();
},
cancelText: this.$i18n.get('cancel'),
confirmText: this.$i18n.get('continue'),
type: 'is-secondary'
});
} else {
next()
}
},
methods: {
...mapActions('category', [
'fetchTerms',
'updateTerm',
'deleteTerm'
]),
...mapGetters('category',[
'getTerms'
]),
addNewTerm() {
let newTerm = {
categoryId: this.categoryId,
name: '',
description: '',
parent: 0,
id: 'new'
}
this.termsList.push(newTerm);
this.editTerm(newTerm);
},
editTerm(term) {
// Closing collapse
if (this.openedTermId == term.id) {
this.openedTermId = '';
// Opening collapse
} else {
this.openedTermId = term.id;
// First time opening
if (this.editForms[this.openedTermId] == undefined) {
this.editForms[this.openedTermId] = JSON.parse(JSON.stringify(term));
this.editForms[this.openedTermId].saved = true;
if (term.id == 'new')
this.editForms[this.openedTermId].saved = false;
}
}
},
removeTerm(term) {
if (term.id == 'new') {
let index = this.termsList.findIndex(deletedTerm => deletedTerm.id == 'new');
if (index >= 0) {
this.termsList.splice(index, 1);
}
if (this.openedTermId == 'new')
this.openedTermId = '';
delete this.editForms['new'];
} else {
this.deleteTerm({categoryId: this.categoryId, termId: term.id})
.then(() => {
})
.catch((error) => {
this.$console.log(error);
});
}
},
onTermEditionFinished() {
let index = this.termsList.findIndex(deletedTerm => deletedTerm.id == 'new');
if (index >= 0) {
this.termsList.splice(index, 1);
}
this.formWithErrors = '';
delete this.editForms[this.openedTermId];
this.openedTermId = '';
},
onTermEditionCanceled() {
this.formWithErrors = '';
delete this.editForms[this.openedTermId];
this.openedTermId = '';
},
buildOrderedTermsList(parentId, termDepth) {
for (let term of this.termsList) {
if (term.parent != parentId ) {
continue;
}
term.depth = termDepth;
this.orderedTermsList.push(term);
this.buildOrderedTermsList(term.id, termDepth + 1);
}
},
generateOrderedTerms() {
this.orderedTermsList = new Array();
this.buildOrderedTermsList(0, 0);
this.$console.log(this.orderedTermsList);
}
},
created() {
this.isLoadingTerms = true;
this.fetchTerms(this.categoryId)
.then(() => {
// Fill this.form data with current data.
this.isLoadingTerms = false;
this.generateOrderedTerms();
})
.catch((error) => {
this.$console.log(error);
});
}
}
</script>
<style lang="scss">
@import "../../scss/_variables.scss";
.loading-spinner {
animation: spinAround 500ms infinite linear;
border: 2px solid #dbdbdb;
border-radius: 290486px;
border-right-color: transparent;
border-top-color: transparent;
content: "";
display: inline-block;
height: 1em;
width: 1em;
}
.term-item {
font-size: 14px;
background-color: white;
padding: 0.7em 0.9em;
margin: 4px;
min-height: 40px;
display: block;
position: relative;
cursor: grab;
.handle {
padding-right: 6em;
}
.grip-icon {
fill: $gray;
top: 2px;
position: relative;
}
.term-name {
text-overflow: ellipsis;
overflow-x: hidden;
white-space: nowrap;
font-weight: bold;
margin-left: 0.4em;
margin-right: 0.4em;
&.is-danger {
color: $danger !important;
}
}
.label-details {
font-weight: normal;
color: $gray;
}
.not-saved {
font-style: italic;
font-weight: bold;
color: $danger;
}
.controls {
position: absolute;
right: 5px;
top: 10px;
.icon {
bottom: 1px;
position: relative;
i, i:before { font-size: 20px; }
}
}
&.not-sortable-item, &.not-sortable-item:hover {
cursor: default;
background-color: white !important;
.handle .label-details, .handle .icon {
color: $gray !important;
}
}
&.not-focusable-item, &.not-focusable-item:hover {
cursor: default;
.term-name {
color: $primary;
}
.handle .label-details, .handle .icon {
color: $gray !important;
}
}
}
.term-item:hover:not(.not-sortable-item) {
background-color: $secondary;
border-color: $secondary;
color: white !important;
.label-details, .icon, .not-saved {
color: white !important;
}
.grip-icon {
fill: white;
}
}
</style>

View File

@ -1,11 +1,25 @@
<template>
<nav id="primary-menu" :class="isCompressed ? 'is-compressed' : ''" role="navigation" :aria-label="$i18n.get('label_main_menu')" class="column is-sidebar-menu">
<nav
id="primary-menu"
:class="isCompressed ? 'is-compressed' : ''"
role="navigation"
:aria-label="$i18n.get('label_main_menu')"
class="column is-sidebar-menu">
<aside class="menu">
<div class="menu-header">
<ul class="menu-list"><li><router-link tag="a" to="/">
<b-icon size="is-medium" icon="chevron-left"></b-icon>
<img class="tainacan-logo" alt="Tainacan Logo" :src="logoHeader"/>
</router-link></li></ul>
<ul class="menu-list"><li>
<router-link
tag="a"
to="/">
<b-icon
size="is-medium"
icon="chevron-left"/>
<img
class="tainacan-logo"
alt="Tainacan Logo"
:src="logoHeader">
</router-link>
</li></ul>
</div>
<ul class="menu-list">
@ -15,32 +29,65 @@
:placeholder="$i18n.get('search')"
type="search"
size="is-small"
icon="magnify">
</b-input>
icon="magnify"/>
</b-field>
<router-link tag="a" to="">
<b-icon size="is-small" icon="magnify"></b-icon> <span class="menu-text">{{ $i18n.get('advanced_search')}}</span>
<router-link
tag="a"
to="">
<b-icon
size="is-small"
icon="magnify"/> <span class="menu-text">{{ $i18n.get('advanced_search') }}</span>
</router-link>
</li>
<li class="separator"></li>
<li><router-link tag="a" to="/collections" :class="activeRoute == 'CollectionsPage' || isCompressed ? 'is-active':''">
<b-icon size="is-small" icon="folder-multiple"></b-icon> <span class="menu-text">{{ $i18n.getFrom('collections', 'name') }}</span>
<li class="separator"/>
<li><router-link
tag="a"
to="/collections"
:class="activeRoute == 'CollectionsPage' || isCompressed ? 'is-active':''">
<b-icon
size="is-small"
icon="folder-multiple"/> <span class="menu-text">{{ $i18n.getFrom('collections', 'name') }}</span>
</router-link></li>
<li><router-link tag="a" to="/items" :class="activeRoute == 'ItemsPage' ? 'is-active':''">
<b-icon size="is-small" icon="file-multiple"></b-icon> <span class="menu-text">{{ $i18n.getFrom('items', 'name') }}</span>
<li><router-link
tag="a"
to="/items"
:class="activeRoute == 'ItemsPage' ? 'is-active':''">
<b-icon
size="is-small"
icon="file-multiple"/> <span class="menu-text">{{ $i18n.getFrom('items', 'name') }}</span>
</router-link></li>
<li class="separator"></li>
<li><router-link tag="a" to="/fields" :class="activeRoute == 'FieldsPage' ? 'is-active':''">
<b-icon size="is-small" icon="format-list-checks"></b-icon> <span class="menu-text">{{ $i18n.getFrom('fields', 'name') }}</span>
<li class="separator"/>
<li><router-link
tag="a"
to="/fields"
:class="activeRoute == 'FieldsPage' ? 'is-active':''">
<b-icon
size="is-small"
icon="format-list-checks"/> <span class="menu-text">{{ $i18n.getFrom('fields', 'name') }}</span>
</router-link></li>
<li><router-link tag="a" to="/filters" :class="activeRoute == 'FiltersPage' ? 'is-active':''">
<b-icon size="is-small" icon="filter"></b-icon> <span class="menu-text">{{ $i18n.getFrom('filters', 'name') }}</span>
<li><router-link
tag="a"
to="/filters"
:class="activeRoute == 'FiltersPage' ? 'is-active':''">
<b-icon
size="is-small"
icon="filter"/> <span class="menu-text">{{ $i18n.getFrom('filters', 'name') }}</span>
</router-link></li>
<li><router-link tag="a" to="/categories" :class="activeRoute == 'CategoriesPage' ? 'is-active':''">
<b-icon size="is-small" icon="shape"></b-icon> <span class="menu-text">{{ $i18n.getFrom('categories', 'name') }}</span>
<li><router-link
tag="a"
to="/categories"
:class="activeRoute == 'CategoriesPage' ? 'is-active':''">
<b-icon
size="is-small"
icon="shape"/> <span class="menu-text">{{ $i18n.getFrom('categories', 'name') }}</span>
</router-link></li>
<li><router-link tag="a" to="/events" :class="activeRoute == 'EventsPage' ? 'is-active':''">
<b-icon size="is-small" icon="bell"></b-icon> <span class="menu-text">{{ $i18n.get('events') }}</span>
<li><router-link
tag="a"
to="/events"
:class="activeRoute == 'EventsPage' ? 'is-active':''">
<b-icon
size="is-small"
icon="bell"/> <span class="menu-text">{{ $i18n.get('events') }}</span>
</router-link></li>
</ul>
</aside>
@ -58,7 +105,7 @@ export default {
}
},
watch: {
'$route' (to, from) {
'$route' (to) {
this.isCompressed = (to.params.collectionId != undefined);
this.activeRoute = to.name;
}

View File

@ -1,11 +1,25 @@
<template>
<nav id="secondary-menu" role="navigation" :aria-label="$i18n.get('label_collection_menu')" class="column is-sidebar-menu">
<nav
id="secondary-menu"
role="navigation"
:aria-label="$i18n.get('label_collection_menu')"
class="column is-sidebar-menu">
<aside class="menu">
<div class="menu-header">
<ul class="menu-list"><li><router-link tag="a" to="/" target='_blank'>
<b-icon size="is-medium" icon="chevron-left"></b-icon>
<img class="tainacan-logo" alt="Tainacan Logo" :src="logoHeader"/>
</router-link></li></ul>
<ul class="menu-list"><li>
<router-link
tag="a"
to="/"
target='_blank'>
<b-icon
size="is-medium"
icon="chevron-left"/>
<img
class="tainacan-logo"
alt="Tainacan Logo"
:src="logoHeader">
</router-link>
</li></ul>
</div>
<ul class="menu-list">
@ -15,41 +29,52 @@
:placeholder="$i18n.getFrom('items', 'search_items')"
type="search"
size="is-small"
icon="magnify">
</b-input>
icon="magnify"/>
</b-field>
<router-link tag="a" to="">
<b-icon size="is-small" icon="magnify"></b-icon> <span class="menu-text">{{ $i18n.get('advanced_search')}}</span>
<router-link
tag="a"
to="">
<b-icon
size="is-small"
icon="magnify"/> <span class="menu-text">{{ $i18n.get('advanced_search') }}</span>
</router-link>
</li>
<li class="separator"></li>
<li class="separator"/>
<li><router-link
tag="a"
:to="{ path: $routerHelper.getCollectionItemsPath(id, '') }"
:class="activeRoute == 'ItemPage' || activeRoute == 'CollectionItemsPage' || activeRoute == 'ItemEditionForm' || activeRoute == 'ItemCreatePage' ? 'is-active':''"
:aria-label="$i18n.get('label_collection_fields')">
<b-icon size="is-small" icon="file-multiple"></b-icon> <span class="menu-text">{{ $i18n.getFrom('items', 'name') }}</span>
<b-icon
size="is-small"
icon="file-multiple"/> <span class="menu-text">{{ $i18n.getFrom('items', 'name') }}</span>
</router-link></li>
<li><router-link
tag="a"
:to="{ path: $routerHelper.getCollectionEditPath(id) }"
:class="activeRoute == 'CollectionEditionForm' ? 'is-active':''"
:aria-label="$i18n.getFrom('collections','edit_item')">
<b-icon size="is-small" icon="pencil"></b-icon> <span class="menu-text">{{ $i18n.get('edit') }}</span>
<b-icon
size="is-small"
icon="pencil"/> <span class="menu-text">{{ $i18n.get('edit') }}</span>
</router-link></li>
<li><router-link
tag="a"
:to="{ path: $routerHelper.getCollectionFieldsPath(id) }"
:class="activeRoute == 'FieldsList' ? 'is-active':''"
:aria-label="$i18n.get('label_collection_fields')">
<b-icon size="is-small" icon="format-list-checks"></b-icon> <span class="menu-text">{{ $i18n.getFrom('fields', 'name') }}</span>
<b-icon
size="is-small"
icon="format-list-checks"/> <span class="menu-text">{{ $i18n.getFrom('fields', 'name') }}</span>
</router-link></li>
<li><router-link
tag="a"
:to="{ path: $routerHelper.getCollectionFiltersPath(id) }"
:class="activeRoute == 'FiltersList' ? 'is-active':''"
:aria-label="$i18n.get('label_collection_filters')">
<b-icon size="is-small" icon="filter"></b-icon> <span class="menu-text">{{ $i18n.getFrom('filters', 'name') }}</span>
<b-icon
size="is-small"
icon="filter"/> <span class="menu-text">{{ $i18n.getFrom('filters', 'name') }}</span>
</router-link></li>
</ul>
</aside>
@ -69,7 +94,7 @@ export default {
id: Number
},
watch: {
'$route' (to, from) {
'$route' (to) {
this.activeRoute = to.name;
}
},

View File

@ -1,15 +1,24 @@
<template>
<div id="tainacan-header" class="level" :class="{'secondary-page': onSecondaryPage}">
<div
id="tainacan-header"
class="level"
:class="{'secondary-page': onSecondaryPage}">
<div class="level-left">
<div class="level-item">
<h1 class="has-text-weight-bold is-uppercase has-text-primary"><b-icon size="is-small" :icon="currentIcon"></b-icon>{{pageTitle}}</h1>
<h1 class="has-text-weight-bold is-uppercase has-text-primary"><b-icon
size="is-small"
:icon="currentIcon"/>{{ pageTitle }}</h1>
<nav class="breadcrumbs">
<router-link tag="a" :to="$routerHelper.getCollectionsPath()">{{ $i18n.get('repository') }}</router-link> >
<span v-for="(pathItem, index) in arrayRealPath" :key="index">
<router-link
<router-link
tag="a"
:to="'/' + arrayRealPath.slice(0, index + 1).join('/')">
{{ arrayViewPath[index] }}
:to="$routerHelper.getCollectionsPath()">{{ $i18n.get('repository') }}</router-link> >
<span
v-for="(pathItem, index) in arrayRealPath"
:key="index">
<router-link
tag="a"
:to="'/' + arrayRealPath.slice(0, index + 1).join('/')">
{{ arrayViewPath[index] }}
</router-link>
<span v-if="index != arrayRealPath.length - 1"> > </span>
</span>
@ -17,8 +26,10 @@
</div>
</div>
<div class="level-right">
<a class="level-item" :href="wordpressAdmin">
<b-icon icon="close"></b-icon>
<a
class="level-item"
:href="wordpressAdmin">
<b-icon icon="close"/>
</a>
</div>
</div>
@ -71,17 +82,17 @@ export default {
case 'collections':
this.fetchCollectionName(this.arrayRealPath[i])
.then(collectionName => this.arrayViewPath.splice(i, 1, collectionName))
.catch((error) => console.log(error));
.catch((error) => this.$console.error(error));
break;
case 'items':
this.fetchItemTitle(this.arrayRealPath[i])
.then(itemTitle => this.arrayViewPath.splice(i, 1, itemTitle))
.catch((error) => console.log(error));
.catch((error) => this.$console.error(error));
break;
case 'categories':
this.fetchCategoryName(this.arrayRealPath[i])
.then(categoryName => this.arrayViewPath.splice(i, 1, categoryName))
.catch((error) => console.log(error));
.catch((error) => this.$console.error(error));
break;
}
@ -93,7 +104,7 @@ export default {
}
},
watch: {
'$route' (to, from) {
'$route' (to) {
this.onSecondaryPage = (to.params.collectionId != undefined);
this.pageTitle = this.$route.meta.title;
this.currentIcon = this.$route.meta.icon;

View File

@ -1,5 +1,46 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="13" height="13" viewBox="0 0 12.8 12.8" class="grip-icon"><circle cx="1.5" cy="1.5" r="1.5" class="undefined"/><circle cx="6.4" cy="1.5" r="1.5" class="undefined"/><circle cx="11.3" cy="1.5" r="1.5" class="undefined"/><circle cx="1.5" cy="6.4" r="1.5" class="undefined"/><circle cx="6.4" cy="6.4" r="1.5" class="undefined"/><circle cx="11.3" cy="6.4" r="1.5" class="undefined"/><circle cx="1.5" cy="11.3" r="1.5" class="undefined"/><circle cx="6.4" cy="11.3" r="1.5" class="undefined"/><circle cx="11.3" cy="11.3" r="1.5" class="undefined"/></svg>
<svg
xmlns="http://www.w3.org/2000/svg"
width="13"
height="13"
viewBox="0 0 12.8 12.8"
class="grip-icon"><circle
cx="1.5"
cy="1.5"
r="1.5"
class="undefined"/><circle
cx="6.4"
cy="1.5"
r="1.5"
class="undefined"/><circle
cx="11.3"
cy="1.5"
r="1.5"
class="undefined"/><circle
cx="1.5"
cy="6.4"
r="1.5"
class="undefined"/><circle
cx="6.4"
cy="6.4"
r="1.5"
class="undefined"/><circle
cx="11.3"
cy="6.4"
r="1.5"
class="undefined"/><circle
cx="1.5"
cy="11.3"
r="1.5"
class="undefined"/><circle
cx="6.4"
cy="11.3"
r="1.5"
class="undefined"/><circle
cx="11.3"
cy="11.3"
r="1.5"
class="undefined"/></svg>
</template>
<script>

View File

@ -1,9 +1,15 @@
<template>
<span class="help-wrapper">
<a class="help-button" @click="isOpened = !isOpened"><b-icon size="is-small" icon="help-circle-outline"></b-icon></a>
<div class="help-tooltip" :class="{ 'opened': isOpened }">
<a
class="help-button"
@click="isOpened = !isOpened"><b-icon
size="is-small"
icon="help-circle-outline"/></a>
<div
class="help-tooltip"
:class="{ 'opened': isOpened }">
<div class="help-tooltip-header">
<h5>{{ title }}</h5><a @click="isOpened = false"><b-icon icon="close"></b-icon></a>
<h5>{{ title }}</h5><a @click="isOpened = false"><b-icon icon="close"/></a>
</div>
<div class="help-tooltip-body">
<p>{{ (message != '' && message != undefined) ? message : $i18n.get('info_no_description_provided') }}</p>
@ -56,7 +62,7 @@ export default {
border-radius: 10px;
margin: 0px 0px 0px -37px;
position: absolute;
z-index: 99999999999999;
z-index: 999999999999999;
bottom: 100%;
left: 0%;
min-width: 250px;

View File

@ -1,6 +1,6 @@
// Main imports
import Vue from 'vue'
import Buefy from 'buefy'
import Vue from 'vue';
import Buefy from 'buefy';
// Custom elements
import Text from '../../classes/field-types/text/Text.vue';
@ -30,19 +30,23 @@ import HelpButton from '../components/other/help-button.vue';
import draggable from 'vuedraggable'
import store from '../../js/store/store'
import router from './router'
import { I18NPlugin, UserPrefsPlugin, RouterHelperPlugin } from './utilities';
import { I18NPlugin, UserPrefsPlugin, RouterHelperPlugin, ConsolePlugin } from './utilities';
// Changing title of pages
router.beforeEach((to, from, next) => {
document.title = to.meta.title;
next();
});
// Configure and Register Plugins
router.beforeEach((to, from, next) => {
document.title = to.meta.title
next()
});
Vue.use(Buefy);
Vue.use(I18NPlugin);
Vue.use(UserPrefsPlugin);
Vue.use(RouterHelperPlugin);
Vue.use(Buefy);
Vue.use(ConsolePlugin, {visual: false});
// Register Components
/* Fields */
Vue.component('tainacan-text', Text);
Vue.component('tainacan-textarea', Textarea);
Vue.component('tainacan-selectbox', Selectbox);
@ -54,21 +58,20 @@ Vue.component('tainacan-category', Category);
Vue.component('tainacan-form-relationship', FormRelationship);
Vue.component('tainacan-form-category', FormCategory);
Vue.component('tainacan-form-selectbox', FormSelectbox);
Vue.component('tainacan-form-item', TaincanFormItem);
Vue.component('tainacan-filters-list', TaincanFiltersList);
Vue.component('help-button', HelpButton);
Vue.component('draggable', draggable);
/* Filters */
Vue.component('tainacan-filter-custom-interval', FilterCustomInterval);
Vue.component('tainacan-filter-selectbox', FilterSelectbox);
Vue.component('tainacan-filter-autocomplete', FilterAutocomplete);
Vue.component('tainacan-filter-checkbox', FilterCheckbox);
Vue.component('tainacan-filter-taginput', FilterTaginput);
/* Others */
Vue.component('help-button', HelpButton);
Vue.component('draggable', draggable);
new Vue({
el: '#tainacan-admin-app',
store,

34
src/admin/js/mixins.js Normal file
View File

@ -0,0 +1,34 @@
import axios from 'axios';
import qs from 'qs';
export const wpAjax = {
data(){
return {
axiosWPAjax: {},
}
},
created(){
this.axiosWPAjax = axios.create({
baseURL: tainacan_plugin.wp_ajax_url,
});
},
methods: {
getSamplePermalink(id, newTitle, newSlug){
return new Promise((resolve, reject) => {
this.axiosWPAjax.post('', qs.stringify({
action: 'sample-permalink',
post_id: id,
new_title: newTitle,
new_slug: newSlug,
samplepermalinknonce: tainacan_plugin.sample_permalink_nonce,
}))
.then(res => {
resolve(res.data);
})
.catch(error => {
reject(error)
})
});
}
}
};

View File

@ -7,6 +7,53 @@ const wpApi = axios.create({
wpApi.defaults.headers.common['X-WP-Nonce'] = tainacan_plugin.nonce;
// CONSOLE PLUGIN - Allows custom use of console functions and avoids eslint warnings.
export const ConsolePlugin = {};
ConsolePlugin.install = function (Vue, options = { visual: false }) {
Vue.prototype.$console = {
log(something) {
if (options.visual) {
Vue.prototype.$snackbar.open({
message: something,
type: 'is-secondary',
position: 'is-bottom-right',
indefinite: true,
queue: false
});
} else {
console.log(something);
}
},
info(someInfo) {
if (options.visual) {
Vue.prototype.$snackbar.open({
message: someInfo,
type: 'is-primary',
position: 'is-bottom-right',
duration: 5000,
queue: false
});
} else {
console.info(someInfo);
}
},
error(someError) {
if (options.visual) {
Vue.prototype.$snackbar.open({
message: someError,
type: 'is-danger',
position: 'is-bottom-right',
indefinite: true,
queue: false
});
} else {
console.error(someError);
}
}
}
}
// I18N PLUGIN - Allows access to Wordpress translation file.
export const I18NPlugin = {};
I18NPlugin.install = function (Vue, options = {}) {

View File

@ -1,10 +1,14 @@
<template>
<div>
<div class="primary-page page-container-small">
<div class="sub-header" v-if="totalCategories > 0">
<div
class="sub-header"
v-if="totalCategories > 0">
<div class="header-item">
<router-link tag="button" class="button is-secondary"
:to="{ path: $routerHelper.getNewCategoryPath() }">
<router-link
tag="button"
class="button is-secondary"
:to="{ path: $routerHelper.getNewCategoryPath() }">
{{ $i18n.get('new') + ' ' + $i18n.get('category') }}
</router-link>
</div>
@ -13,14 +17,15 @@
<div class="columns above-subheader">
<div class="column table-container">
<categories-list
:isLoading="isLoading"
:totalCategories="totalCategories"
:is-loading="isLoading"
:total-categories="totalCategories"
:page="page"
:categoriesPerPage="categoriesPerPage"
:categories="categories">
</categories-list>
:categories-per-page="categoriesPerPage"
:categories="categories"/>
<!-- Footer -->
<div class="table-footer" v-if="totalCategories > 0">
<div
class="table-footer"
v-if="totalCategories > 0">
<div class="shown-items">
{{
$i18n.get('info_showing_categories') +
@ -31,7 +36,9 @@
}}
</div>
<div class="items-per-page">
<b-field horizontal :label="$i18n.get('label_categories_per_page')">
<b-field
horizontal
:label="$i18n.get('label_categories_per_page')">
<b-select
:value="categoriesPerPage"
@input="onChangeCategoriesPerPage"
@ -50,8 +57,7 @@
:current.sync="page"
order="is-centered"
size="is-small"
:per-page="categoriesPerPage">
</b-pagination>
:per-page="categoriesPerPage"/>
</div>
</div>
</div>
@ -103,7 +109,7 @@
this.isLoading = false;
this.totalCategories = res.total;
})
.catch((error) => {
.catch(() => {
this.isLoading = false;
});
},
@ -126,7 +132,7 @@
.then((value) => {
this.categoriesPerPage = value;
})
.catch((error) => {
.catch(() => {
this.$userPrefs.set('categories_per_page', 12, null);
});
},

View File

@ -2,8 +2,10 @@
<div class="primary-page page-container-small">
<div class="sub-header">
<div class="header-item">
<router-link tag="button" class="button is-secondary"
:to="{ path: $routerHelper.getNewCollectionPath() }">
<router-link
tag="button"
class="button is-secondary"
:to="{ path: $routerHelper.getNewCollectionPath() }">
{{ $i18n.getFrom('collections', 'new_item') }}
</router-link>
</div>
@ -14,12 +16,11 @@
</aside>
<div class="column table-container">
<collections-list
:isLoading="isLoading"
:totalCollections="totalCollections"
:page="page"
:collectionsPerPage="collectionsPerPage"
:collections="collections">
</collections-list>
:is-loading="isLoading"
:total-collections="totalCollections"
:page="page"
:collections-per-page="collectionsPerPage"
:collections="collections"/>
<!-- Footer -->
<div class="table-footer">
<div class="shown-items">
@ -32,7 +33,9 @@
}}
</div>
<div class="items-per-page">
<b-field horizontal :label="$i18n.get('label_collections_per_page')">
<b-field
horizontal
:label="$i18n.get('label_collections_per_page')">
<b-select
:value="collectionsPerPage"
@input="onChangeCollectionsPerPage"
@ -46,13 +49,12 @@
</div>
<div class="pagination">
<b-pagination
@change="onPageChange"
:total="totalCollections"
:current.sync="page"
order="is-centered"
size="is-small"
:per-page="collectionsPerPage">
</b-pagination>
@change="onPageChange"
:total="totalCollections"
:current.sync="page"
order="is-centered"
size="is-small"
:per-page="collectionsPerPage"/>
</div>
</div>
</div>
@ -103,7 +105,7 @@ export default {
this.isLoading = false;
this.totalCollections = res.total;
})
.catch((error) => {
.catch(() => {
this.isLoading = false;
});
},
@ -126,7 +128,7 @@ export default {
.then((value) => {
this.collectionsPerPage = value;
})
.catch((error) => {
.catch(() => {
this.$userPrefs.set('collections_per_page', 12, null);
});
},

View File

@ -1,6 +1,6 @@
<template>
<div class="primary-page page-container">
<fields-list></fields-list>
<fields-list/>
</div>
</template>

View File

@ -1,6 +1,6 @@
<template>
<div class="primary-page page-container">
<filters-list></filters-list>
<filters-list/>
</div>
</template>

View File

@ -1,25 +1,34 @@
<template>
<div class="page-container-small" :class="{'primary-page': isRepositoryLevel}">
<div
class="page-container-small"
:class="{'primary-page': isRepositoryLevel}">
<div class="sub-header">
<div class="header-item">
<router-link tag="button" class="button is-secondary"
<router-link
tag="button"
class="button is-secondary"
:to="{ path: $routerHelper.getNewItemPath(collectionId) }">
{{ $i18n.getFrom('items', 'new_item') }}
</router-link>
</div>
<div class="header-item">
<b-dropdown>
<button class="button" slot="trigger" :disabled="items.length <= 0">
<span>{{$i18n.get('label_table_fields')}}</span>
<b-icon icon="menu-down"></b-icon>
<button
class="button"
slot="trigger"
:disabled="items.length <= 0">
<span>{{ $i18n.get('label_table_fields') }}</span>
<b-icon icon="menu-down"/>
</button>
<b-dropdown-item v-for="(column, index) in tableFields"
:key="index"
class="control" custom>
<b-dropdown-item
v-for="(column, index) in tableFields"
:key="index"
class="control"
custom>
<b-checkbox
@input="onChangeTableFields(column)"
v-model="column.visible"
:native-value="column.field">
@input="onChangeTableFields(column)"
v-model="column.visible"
:native-value="column.field">
{{ column.label }}
</b-checkbox>
</b-dropdown-item>
@ -29,19 +38,18 @@
<div class="columns above-subheader">
<aside class="column filters-menu">
<h3>{{ $i18n.get('filters') }}</h3>
<filters-items-list></filters-items-list>
<filters-items-list/>
</aside>
<div class="column table-container">
<items-list
:collection-id="collectionId"
:tableFields="tableFields"
:prefTableFields="prefTableFields"
:totalItems="totalItems"
:page="page"
:items="items"
:isLoading="isLoading"
:itemsPerPage="itemsPerPage">
</items-list>
:collection-id="collectionId"
:table-fields="tableFields"
:pref-table-fields="prefTableFields"
:total-items="totalItems"
:page="page"
:items="items"
:is-loading="isLoading"
:items-per-page="itemsPerPage"/>
<!-- Footer -->
<div class="table-footer">
<div class="shown-items">
@ -54,7 +62,9 @@
}}
</div>
<div class="items-per-page">
<b-field horizontal :label="$i18n.get('label_items_per_page')">
<b-field
horizontal
:label="$i18n.get('label_items_per_page')">
<b-select
:value="itemsPerPage"
@input="onChangeItemsPerPage"
@ -68,13 +78,12 @@
</div>
<div class="pagination">
<b-pagination
@change="onPageChange"
:total="totalItems"
:current.sync="page"
order="is-centered"
size="is-small"
:per-page="itemsPerPage">
</b-pagination>
@change="onPageChange"
:total="totalItems"
:current.sync="page"
order="is-centered"
size="is-small"
:per-page="itemsPerPage"/>
</div>
</div>
</div>
@ -135,7 +144,7 @@ export default {
'search_by_collection'
]),
onChangeTableFields(field) {
let prevValue = this.prefTableFields;
// let prevValue = this.prefTableFields;
let index = this.prefTableFields.findIndex(alteredField => alteredField.slug === field.slug);
if (index >= 0) {
//prevValue[index].visible = this.prefTableFields[index].visible ? false : true;
@ -143,12 +152,12 @@ export default {
// for (let currentField of this.prefTableFields)
// console.log(currentField.slug, currentField.visible);
// this.$console.log(currentField.slug, currentField.visible);
// for (let oldField of prevValue)
// console.log(oldField.slug, oldField.visible);
// this.$console.log(oldField.slug, oldField.visible);
//this.$userPrefs.set('table_columns_' + this.collectionId, this.prefTableFields, prevValue);
},
@ -187,11 +196,10 @@ export default {
this.alterQueryString();
}
promisse.then((res) => {
promisse.then(() => {
this.isLoading = false;
})
.catch((error) => {
.catch(() => {
this.isLoading = false;
});
},
@ -233,7 +241,7 @@ export default {
.then((value) => {
this.itemsPerPage = value;
})
.catch((error) => {
.catch(() => {
this.$userPrefs.set('items_per_page', 12, null);
});
},
@ -307,11 +315,12 @@ export default {
background-color: $primary-lighter;
margin-left: -$page-small-side-padding;
padding: $page-small-side-padding;
.label {
font-size: 12px;
font-weight: normal;
font-size: 0.85em;
}
}
.table-container {

View File

@ -16,6 +16,9 @@
:to="{ path: $routerHelper.getCategoryEditPath(categoryId)}">
{{ $i18n.get('edit') + ' ' + $i18n.get('category') }}
</router-link>
<a class="card-footer-item">
Edit terms
</a>
</footer>
</div>
</div>

View File

@ -1,8 +1,8 @@
<template>
<div class="columns is-fullheight">
<secondary-menu :id="collectionId"></secondary-menu>
<secondary-menu :id="collectionId"/>
<section class="column is-secondary-content">
<router-view class="page-container"></router-view>
<router-view class="page-container"/>
</section>
</div>
</template>
@ -17,8 +17,6 @@ export default {
collectionId: Number
}
},
methods: {
},
components: {
SecondaryMenu
},

View File

@ -1,12 +1,17 @@
<template>
<div>
<b-loading :active.sync="isLoading" :canCancel="false">
</b-loading>
<b-loading
:active.sync="isLoading"
:can-cancel="false"/>
<div class="card">
<div class="card-image" v-if="item.featured_image">
<div
class="card-image"
v-if="item.featured_image">
<figure class="image is-4by3">
<img :src="item.featured_image" class="image" :alt="item.title">
<img
:src="item.featured_image"
class="image"
:alt="item.title">
</figure>
</div>
<div class="card-content">
@ -18,16 +23,18 @@
</div>
<div class="content">
{{item.description}}
{{ item.description }}
</div>
</div>
<footer class="card-footer">
<router-link
class="card-footer-item" :to="{ path: $routerHelper.getCollectionPath(collectionId)}">
class="card-footer-item"
:to="{ path: $routerHelper.getCollectionPath(collectionId)}">
{{ $i18n.get('see') + ' ' + $i18n.get('collection') }}
</router-link>
<router-link
class="card-footer-item" :to="{ path: $routerHelper.getItemEditPath(collectionId, itemId)}">
class="card-footer-item"
:to="{ path: $routerHelper.getItemEditPath(collectionId, itemId)}">
{{ $i18n.get('edit') + ' ' + $i18n.get('item') }}
</router-link>
</footer>
@ -70,7 +77,7 @@ export default {
let loadingInstance = this;
// Obtains Item
this.fetchItem(this.itemId).then(res => {
this.fetchItem(this.itemId).then(() => {
loadingInstance.isLoading = false;
});
}

View File

@ -70,9 +70,9 @@ html {
}
}
// Buefy notices (toast)
// Buefy notices (toast, snackbar...)
.notices {
z-index: 99999999 !important;
z-index: 99999999999999 !important;
}
// Input components used in forms are gray in Tainacan

View File

@ -67,6 +67,10 @@ return [
'title_collection_fields_edition' => __( 'Collection Fields Edition Page', 'tainacan' ),
// Labels (used mainly on Aria Labels and Inputs)
'label_clean' => __( 'Clear', 'tainacan' ),
'label_selected' => __( 'Selected', 'tainacan' ),
'label_relationship_new_search' => __( 'New Search', 'tainacan' ),
'label_relationship_items_found' => __( 'Items found', 'tainacan' ),
'label_menu' => __( 'Menu', 'tainacan' ),
'label_main_menu' => __( 'Main Menu', 'tainacan' ),
'label_collection_menu' => __( 'Collection Menu', 'tainacan' ),
@ -117,7 +121,9 @@ return [
'label_collection_fields' => __( 'Collection Fields', 'tainacan' ),
'label_collection_filters' => __( 'Collection Filters', 'tainacan' ),
'label_parent_term' => __( 'Parent Term', 'tainacan' ),
'label_add_new_term' => __( 'Add New Term', 'tainacan' ),
'label_new_term' => __( 'New Term', 'tainacan' ),
'label_category_terms' => __( 'Category Terms', 'tainacan' ),
'label_no_parent_term' => __( 'No parent term', 'tainacan' ),
// Instructions. More complex sentences to guide user and placeholders
'instruction_dragndrop_fields_collection' => __( 'Drag and drop Fields here to Collection.', 'tainacan' ),
@ -130,6 +136,7 @@ return [
'instruction_image_upload_box' => __( 'Drop an image here or click to upload.', 'tainacan' ),
'instruction_select_a_status' => __( 'Select a status:', 'tainacan' ),
'instruction_select_a_filter_type' => __( 'Select a filter type:', 'tainacan' ),
'instruction_select_a_parent_term' => __( 'Select a parent term:', 'tainacan' ),
// Info. Other feedback to user.
'info_name_is_required' => __( 'Name is required.', 'tainacan' ),
@ -137,10 +144,13 @@ return [
'info_no_category_created' => __( 'No category was created in this repository.', 'tainacan' ),
'info_no_item_created' => __( 'No item was created in this collection.', 'tainacan' ),
'info_error_deleting_collection' => __( 'Error on deleting collection.', 'tainacan' ),
'info_error_deleting_category' => __( 'Error on deleting category', 'tainacan' ),
'info_collection_deleted' => __( 'Collection deleted.', 'tainacan' ),
'info_item_deleted' => __( 'Item deleted.', 'tainacan' ),
'info_category_deleted' => __( 'Category deleted', 'tainacan' ),
'info_warning_collection_delete' => __( 'Do you really want to delete this collection?', 'tainacan' ),
'info_warning_item_delete' => __( 'Do you really want to delete this item?', 'tainacan' ),
'info_warning_category_delete' => __( 'Do you really want to delete this category?', 'tainacan' ),
'info_warning_selected_collections_delete' => __( 'Do you really want to delete the selected collections?', 'tainacan' ),
'info_warning_selected_items_delete' => __( 'Do you really want to delete the selected items?', 'tainacan' ),
'info_warning_collection_related' => __( 'The field Collection related is required', 'tainacan' ),
@ -156,6 +166,7 @@ return [
'info_warning_fields_not_saved' => __('Are you sure? There are fields not saved, changes will be lost.', 'tainacan'),
'info_warning_filters_not_saved' => __('Are you sure? There are filters not saved, changes will be lost.', 'tainacan'),
'info_no_description_provided' => __('No description provided.', 'tainacan'),
'info_warning_terms_not_saved' => __('Are you sure? There are terms not saved, changes will be lost.', 'tainacan'),
// Tainacan Field Types
'tainacan-text' => __( 'Text', 'tainacan' ),

View File

@ -95,7 +95,8 @@ class TAINACAN_REST_Controller extends WP_REST_Controller {
'hideempty' => 'hide_empty',
'perpage' => 'posts_per_page',
'paged' => 'paged',
'postin' => 'post__in'
'postin' => 'post__in',
'relation' => 'relation'
];
$meta_query = [
@ -247,9 +248,26 @@ class TAINACAN_REST_Controller extends WP_REST_Controller {
private function prepare_meta($mapped, $request, $query, $mapped_v, $args){
$request_meta_query = $request[$mapped];
// if the meta/date/taxquery has a root relation
if( isset( $request_meta_query['relation']) )
$args[ $mapped_v ]['relation'] = $request_meta_query['relation'];
// If is a multidimensional array (array of array)
if($this->contains_array($request_meta_query, $query)) {
foreach ( $request_meta_query as $index1 => $a ) {
// handle core field
if( array_key_exists("key", $a) ){
$field = new Tainacan\Entities\Field($a['key']);
if( strpos( $field->get_field_type(), 'Core') !== false ){
$args[ 'post_title_in' ] = [
'relation' => ( isset( $request_meta_query['relation']) ) ? $request_meta_query['relation'] : 'AND' ,
'value' => ( is_array( $a['value'] ) ) ? $a['value'] : [$a['value']]
];
continue;
}
}
foreach ( $query as $mapped_meta => $meta_v ) {
if ( isset( $a[ $meta_v ] ) ) {
$args[ $mapped_v ][ $index1 ][ $meta_v ] = $request[ $mapped ][ $index1 ][ $meta_v ];

View File

@ -68,8 +68,8 @@ class TAINACAN_REST_Collections_Controller extends TAINACAN_REST_Controller {
'callback' => array($this, 'delete_item'),
'permission_callback' => array($this, 'delete_item_permissions_check'),
'args' => array(
'body_args' => array(
'description' => __('To delete permanently, in body you can pass \'is_permanently\' as true. By default this will only trash collection'),
'permanently' => array(
'description' => __('To delete permanently, you can pass \'permanently\' as true. By default this will only trash collection'),
'default' => 'false'
),
)
@ -275,9 +275,9 @@ class TAINACAN_REST_Collections_Controller extends TAINACAN_REST_Controller {
*/
public function delete_item( $request ) {
$collection_id = $request['collection_id'];
$is_permanently = json_decode($request->get_body(), true);
$permanently = $request['permanently'];
$args = [$collection_id, $is_permanently];
$args = [$collection_id, $permanently];
$collection = $this->collections_repository->delete($args);

View File

@ -78,8 +78,8 @@ class TAINACAN_REST_Filters_Controller extends TAINACAN_REST_Controller {
'callback' => array($this, 'delete_item'),
'permission_callback' => array($this, 'delete_item_permissions_check'),
'args' => array(
'body_args' => array(
'description' => __('To delete permanently, in body you can pass \'is_permanently\' as true. By default this will only trash collection'),
'permanently' => array(
'description' => __('To delete permanently, you can pass \'permanently\' as true. By default this will only trash collection'),
'default' => 'false'
),
)
@ -218,21 +218,13 @@ class TAINACAN_REST_Filters_Controller extends TAINACAN_REST_Controller {
*/
public function delete_item( $request ) {
$filter_id = $request['filter_id'];
$permanently = $request['permanently'];
$is_permanently = json_decode($request->get_body(), true);
$args = [$filter_id, $permanently];
if(!empty($is_permanently)){
$args = [$filter_id, $is_permanently];
$filter = $this->filter_repository->delete($args);
$filter = $this->filter_repository->delete($args);
return new WP_REST_Response($this->prepare_item_for_response($filter, $request), 200);
}
return new WP_REST_Response([
'error_message' => __('The body could not be empty', 'tainacan'),
'body' => $request->get_body()
], 400);
return new WP_REST_Response($this->prepare_item_for_response($filter, $request), 200);
}
/**

View File

@ -77,8 +77,8 @@ class TAINACAN_REST_Items_Controller extends TAINACAN_REST_Controller {
'callback' => array($this, 'delete_item'),
'permission_callback' => array($this, 'delete_item_permissions_check'),
'args' => array(
'body_args' => array(
'description' => __('To delete permanently, in body you can pass \'is_permanently\' as true. By default this will only trash collection'),
'permanently' => array(
'description' => __('To delete permanently, you can pass \'permanently\' as true. By default this will only trash collection'),
'default' => 'false'
),
)
@ -306,10 +306,10 @@ class TAINACAN_REST_Items_Controller extends TAINACAN_REST_Controller {
* @return WP_Error|WP_REST_Response
*/
public function delete_item( $request ) {
$item_id = $request['item_id'];
$is_permanently = json_decode($request->get_body(), true);
$item_id = $request['item_id'];
$permanently = $request['permanently'];
$args = [$item_id, $is_permanently];
$args = [$item_id, $permanently];
$item = $this->items_repository->delete($args);

View File

@ -58,9 +58,9 @@ class TAINACAN_REST_Taxonomies_Controller extends TAINACAN_REST_Controller {
'callback' => array($this, 'delete_item'),
'permission_callback' => array($this, 'delete_item_permissions_check'),
'args' => array(
'body_args' => array(
'description' => __('To delete permanently, in body you can pass \'is_permanently\' as true. By default this will only trash collection'),
'default' => 'false'
'permanently' => array(
'description' => __('To delete permanently, you can pass \'permanently\' as true. By default this will only trash collection'),
'default' => 'false',
),
)
),
@ -164,22 +164,14 @@ class TAINACAN_REST_Taxonomies_Controller extends TAINACAN_REST_Controller {
*/
public function delete_item( $request ) {
$taxonomy_id = $request['taxonomy_id'];
if(empty($request->get_body())){
return new WP_REST_Response([
'error_message' => __('Body can not be empty.', 'tainacan'),
'body' => $request->get_body()
], 400);
}
$is_permanently = json_decode($request->get_body(), true);
$permanently = $request['permanently'];
$taxonomy = $this->taxonomy_repository->fetch($taxonomy_id);
if(!empty($taxonomy)) {
$taxonomy_name = $taxonomy->get_db_identifier();
$args = [ $taxonomy_id, $taxonomy_name, $is_permanently ];
$args = [ $taxonomy_id, $taxonomy_name, $permanently ];
$deleted = $this->taxonomy_repository->delete( $args );

View File

@ -45,6 +45,19 @@ class Term extends Entity {
return 'Hello, my name is '. $this->get_name();
}
public function __toArray(){
$term_array = parent::__toArray();
$term_id = $term_array['term_id'];
unset($term_array['term_id']);
unset($term_array['status']);
$term_array['id'] = $term_id;
return $term_array;
}
// Getters
/**

View File

@ -2,8 +2,10 @@
<div>
<span>
<a
class="button"
@click="showForm = !showForm"><b-icon size="is-small" icon="plus"></b-icon>&nbsp;{{ $i18n.get('label_add_new_term') }}</a>
class="button"
@click="showForm = !showForm"><b-icon
size="is-small"
icon="plus"/>&nbsp;{{ $i18n.get('label_add_new_term') }}</a>
</span>
<div class="columns">
<transition name="fade">
@ -14,24 +16,26 @@
style="padding-left: 0px;">
<b-field :label="$i18n.get('label_name')">
<b-input v-model="name"></b-input>
<b-input 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
:value="0"
selected> ---{{ $i18n.get('label_parent_term') }}--- </option>
<option
v-for="option,index in options"
v-for="(option,index) in options"
:key="index"
:value="option.term_id"
v-html="setSpaces( option.level ) + option.name"></option>
: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>
class="button is-primary"
@click="save">{{ $i18n.get('save') }}</a>
</section>
</transition>
@ -90,22 +94,22 @@
instance.name = '';
instance.parent = 0;
if( res.data && res.data.term_id || res.term_id ){
let term_id = ( res.term_id ) ? res.term_id : res.data.term_id;
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.field.field.multiple === 'no' ){
axios.patch(`/item/${this.item_id}/metadata/${this.field_id}`, {
values: term_id,
}).then( res => {
instance.$emit('newTerm', term_id);
values: id,
}).then(() => {
instance.$emit('newTerm', id);
})
} else {
val = ( val ) ? val : [];
val.push( term_id );
val.push( id );
axios.patch(`/item/${this.item_id}/metadata/${this.field_id}`, {
values: val,
}).then( res => {
}).then( () => {
instance.$emit('newTerm', val);
})
}

View File

@ -3,9 +3,9 @@
<component
:is="getComponent()"
v-model="valueComponent"
:allowNew="allowNew"
:allow-new="allowNew"
:terms="terms"
:options="getOptions(0)"></component>
:options="getOptions(0)"/>
<add-new-term
class="add-new-term"
v-if="getComponent() !== 'tainacan-category-tag-input' && allowNew"
@ -14,7 +14,7 @@
:item_id="field.item.id"
:value="valueComponent"
:options="getOptions(0)"
@newTerm="reload"></add-new-term>
@newTerm="reload"/>
</div>
</template>
<script>
@ -88,7 +88,7 @@
}
})
.catch(error => {
console.log(error);
this.$console.log(error);
});
},
getOptions( parent, level = 0 ){ // retrieve only ids
@ -99,7 +99,7 @@
term['level'] = level;
result.push( term );
const levelTerm = level + 1;
const children = this.getOptions( term.term_id, levelTerm);
const children = this.getOptions( term.id, levelTerm);
result = result.concat( children );
}
}
@ -110,8 +110,8 @@
let values = [];
if( this.value && this.value.length > 0){
for( let term of this.value ){
if( term && term.term_id)
values.push(term.term_id);
if( term && term.id)
values.push(term.id);
}
}

View File

@ -1,13 +1,15 @@
<template>
<div>
<div v-for="option,index in options">
<div
v-for="(option, index) in options"
:key="index">
<b-checkbox
:id="id"
:style="{ paddingLeft: (option.level * 30) + 'px' }"
:style="{ paddingLeft: (option.level * 30) + 'px' }"
:key="index"
v-model="checked"
@input="onChecked(option)"
:native-value="option.term_id"
:native-value="option.id"
border>
{{ option.name }}
</b-checkbox>
@ -40,7 +42,7 @@
value: [ Number, String, Array ]
},
methods: {
onChecked(option) {
onChecked() {
this.$emit('blur');
this.onInput(this.checked)
},

View File

@ -1,13 +1,15 @@
<template>
<div>
<div v-for="option,index in options">
<div
v-for="(option, index) in options"
:key="index">
<b-radio
:id="id"
:style="{ paddingLeft: (option.level * 30) + 'px' }"
:style="{ paddingLeft: (option.level * 30) + 'px' }"
:key="index"
v-model="checked"
@input="onChecked(option)"
:native-value="option.term_id"
:native-value="option.id"
border>
{{ option.name }}
</b-radio>
@ -36,7 +38,7 @@
value: [ Number, String, Array ]
},
methods: {
onChecked(option) {
onChecked() {
this.$emit('blur');
this.onInput(this.checked)
},

View File

@ -5,12 +5,13 @@
:id="id"
v-model="selected"
@input="emitChange()"
:placeholder="$i18n.get('label_select_category')" expanded>
:placeholder="$i18n.get('label_select_category')"
expanded>
<option
v-for="option,index in options"
v-for="(option, index) in options"
:key="index"
:value="option.term_id"
v-html="setSpaces( option.level ) + option.name"></option>
:value="option.id"
v-html="setSpaces( option.level ) + option.name"/>
</b-select>
</div>
</div>

View File

@ -4,14 +4,13 @@
size="is-small"
rounded
icon="magnify"
:allowNew="allowNew"
:allow-new="allowNew"
@input="emitChange"
v-model="selected"
:data="labels"
field="label"
autocomplete
@typing="search">
</b-taginput>
@typing="search"/>
</div>
</template>
<script>
@ -23,7 +22,7 @@
}
},
watch: {
terms( val ){
terms(){
this.selectedValues();
}
},
@ -45,20 +44,20 @@
});
this.labels = [];
for( let term of result){
this.labels.push({label: term.name, value: term.term_id})
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.term_id;
let id = item.id;
return ( this.value.indexOf( id ) >= 0 )
});
let selected = [];
for( let term of result){
selected.push({label: term.name, value: term.term_id})
selected.push({label: term.name, value: term.id})
}
this.selected = selected;
}

View File

@ -2,16 +2,15 @@
<section
v-if="isReady"
:listen="setError">
<b-field :addons="false"
:type="taxonomyType"
:message="taxonomyMessage"
>
<b-field
:addons="false"
:type="taxonomyType"
:message="taxonomyMessage">
<label class="label">
{{ $i18n.get('label_select_category') }}<span :class="taxonomyType" >&nbsp;*&nbsp;</span>
<help-button
:title="$i18n.getHelperTitle('tainacan-category', 'taxonomy_id')"
:message="$i18n.getHelperMessage('tainacan-category', 'taxonomy_id')">
</help-button>
:message="$i18n.getHelperMessage('tainacan-category', 'taxonomy_id')"/>
</label>
<b-select
name="field_type_options[taxonomy_id]"
@ -35,8 +34,7 @@
{{ $i18n.get('label_select_category_input_type') }}
<help-button
:title="$i18n.getHelperTitle('tainacan-category', 'input_type')"
:message="$i18n.getHelperMessage('tainacan-category', 'input_type')">
</help-button>
:message="$i18n.getHelperMessage('tainacan-category', 'input_type')"/>
</label>
<b-select
v-if="listInputType"
@ -45,7 +43,7 @@
@input="emitValues()"
v-model="input_type">
<option
v-for="option,index in single_types"
v-for="(option, index) in single_types"
:value="index"
:key="index">
{{ option }}
@ -60,7 +58,7 @@
v-else>
<option
v-for="option,index in multiple_types"
v-for="(option, index) in multiple_types"
:value="index"
:key="index">
{{ option }}
@ -74,14 +72,14 @@
{{ $i18n.get('label_category_allow_new_terms') }}
<help-button
:title="$i18n.getHelperTitle('tainacan-category', 'allow_new_terms')"
:message="$i18n.getHelperMessage('tainacan-category', 'allow_new_terms')">
</help-button>
:message="$i18n.getHelperMessage('tainacan-category', 'allow_new_terms')"/>
</label>
<div class="block">
<b-checkbox v-model="allow_new_terms"
@input="emitValues()"
true-value="yes"
false-value="no">
<b-checkbox
v-model="allow_new_terms"
@input="emitValues()"
true-value="yes"
false-value="no">
{{ labelNewTerms() }}
</b-checkbox>
</div>
@ -102,7 +100,7 @@
errors: [ String, Object, Array ]
},
created(){
this.fetchTaxonomies().then( res => {
this.fetchTaxonomies().then(() => {
if ( this.value ) {
this.taxonomy_id = this.value.taxonomy_id;
}
@ -124,23 +122,22 @@
if( this.field && this.field.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.input_type = ( hasValue ) ? this.value.input_type : 'tainacan-category-radio';
this.setInputType( ( hasValue ) ? this.value.input_type : 'tainacan-category-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.input_type = ( hasValue ) ? this.value.input_type : 'tainacan-category-checkbox';
this.setInputType( ( hasValue ) ? this.value.input_type : 'tainacan-category-checkbox' );
return false;
}
},
setError(){
if( this.errors && this.errors.taxonomy_id !== '' ){
this.taxonomyType = 'is-danger';
this.taxonomyMessage = this.errors.taxonomy_id;
this.setErrorsAttributes( 'is-danger', this.errors.taxonomy_id );
} else {
this.taxonomyType = '';
this.taxonomyMessage = '';
this.setErrorsAttributes( '', '' );
}
return true;
}
},
data(){
@ -158,6 +155,13 @@
}
},
methods: {
setInputType( input ){
this.input_type = input;
},
setErrorsAttributes( type, message ){
this.taxonomyType = type;
this.taxonomyMessage = message;
},
fetchTaxonomies(){
return axios.get('/taxonomies')
.then(res => {
@ -171,8 +175,7 @@
}
})
.catch(error => {
console.log(error);
reject(error);
this.$console.log(error);
});
},
labelNewTerms(){

View File

@ -2,6 +2,10 @@
namespace Tainacan\Field_Types;
use Tainacan\Entities\Field;
use Tainacan\Entities\Item_Metadata_Entity;
use Tainacan\Repositories\Fields;
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
/**
@ -44,7 +48,7 @@ class Category extends Field_Type {
}
/**
* @param $itemMetadata \Tainacan\Entities\Item_Metadata_Entity The instace of the entity itemMetadata
* @param $itemMetadata Item_Metadata_Entity The instace of the entity itemMetadata
* @return string
*/
@ -58,7 +62,7 @@ class Category extends Field_Type {
name="'.$itemMetadata->get_field()->get_name().'"></tainacan-selectbox>';
}
public function validate_options(\Tainacan\Entities\Field $field) {
public function validate_options( Field $field) {
if ( !in_array($field->get_status(), apply_filters('tainacan-status-require-validation', ['publish','future','private'])) )
return true;
@ -66,7 +70,7 @@ class Category extends Field_Type {
if (empty($this->get_option('taxonomy_id')))
return ['taxonomy_id' => __('Please select a category', 'tainacan')];
$Tainacan_Fields = \Tainacan\Repositories\Fields::getInstance();
$Tainacan_Fields = Fields::getInstance();
$category_fields = $Tainacan_Fields->fetch([
'collection_id' => $field->get_collection_id(),
@ -90,18 +94,18 @@ class Category extends Field_Type {
return true;
}
/**
* Validate item based on field type categories options
*
* @param TainacanEntitiesItem_Metadata_Entity $item_metadata
* @return bool Valid or not
*/
public function validate(\Tainacan\Entities\Item_Metadata_Entity $item_metadata) {
* Validate item based on field type categories 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();
$field = $item_metadata->get_field();
if ( !in_array($item->get_status(), apply_filters('tainacan-status-require-validation', ['publish','future','private'])) )
return true;

View File

@ -2,7 +2,7 @@
<b-datepicker
:id="id"
v-model="dateValue"
@input="onInput($event)"></b-datepicker>
@input="onInput($event)"/>
</template>
<script>

View File

@ -6,7 +6,7 @@
step="0.01"
@blur="onBlur"
@change="onBlur"
@input="onInput($event)"></b-input>
@input="onInput($event)"/>
</template>
<script>

View File

@ -9,8 +9,7 @@
{{ $i18n.get('label_collection_related') }}<span :class="collectionType" >&nbsp;*&nbsp;</span>
<help-button
:title="$i18n.getHelperTitle('tainacan-relationship', 'collection_id')"
:message="$i18n.getHelperMessage('tainacan-relationship', 'collection_id')">
</help-button>
:message="$i18n.getHelperMessage('tainacan-relationship', 'collection_id')"/>
</label>
<b-select
name="field_type_relationship[collection_id]"
@ -32,7 +31,7 @@
<transition name="fade">
<div
v-if="loadingFields"
class="loading-spinner"></div>
class="loading-spinner"/>
<b-field
v-if="hasFields"
:addons="false">
@ -40,12 +39,12 @@
{{ $i18n.get('label_fields_for_search') }}
<help-button
:title="$i18n.getHelperTitle('tainacan-relationship', 'search')"
:message="$i18n.getHelperMessage('tainacan-relationship', 'search')">
</help-button>
:message="$i18n.getHelperMessage('tainacan-relationship', 'search')"/>
</label>
<div class="block">
<div
v-for="option in fields"
v-for="(option, index) in fields"
:key="index"
class="field">
<b-checkbox
name="field_type_relationship[search][]"
@ -65,15 +64,15 @@
{{ $i18n.get('label_allow_repeated_items') }}
<help-button
:title="$i18n.getHelperTitle('tainacan-relationship', 'repeated')"
:message="$i18n.getHelperMessage('tainacan-relationship', 'repeated')">
</help-button>
:message="$i18n.getHelperMessage('tainacan-relationship', 'repeated')"/>
</label>
<div class="block">
<b-checkbox v-model="modelRepeated"
@input="emitValues()"
true-value="yes"
false-value="no">
{{ labelRepeated() }}
<b-checkbox
v-model="modelRepeated"
@input="emitValues()"
true-value="yes"
false-value="no">
{{ labelRepeated() }}
</b-checkbox>
</div>
</b-field>
@ -82,7 +81,6 @@
<script>
import { tainacan as axios } from '../../../js/axios/axios';
import Vue from 'vue';
export default {
props: {
@ -125,7 +123,7 @@
}
},
created(){
this.fetchCollections().then( data => {
this.fetchCollections().then(() => {
if( this.collection_id && this.collection_id !== '' ){
this.collection = this.collection_id;
} else if ( this.value ) {
@ -142,15 +140,18 @@
computed: {
setError(){
if( this.errors && this.errors.collection_id !== '' ){
this.collectionType = 'is-danger';
this.collectionMessage = this.errors.collection_id;
this.setErrorsAttributes( 'is-danger', this.errors.collection_id );
} else {
this.collectionType = '';
this.collectionMessage = '';
this.setErrorsAttributes( '', '' );
}
return true;
},
},
methods:{
setErrorsAttributes( type, message ){
this.collectionType = type;
this.collectionType = message;
},
fetchCollections(){
return axios.get('/collections')
.then(res => {
@ -164,8 +165,7 @@
}
})
.catch(error => {
console.log(error);
reject(error);
this.$console.log(error);
});
},
fetchFieldsFromCollection( value ){
@ -198,7 +198,7 @@
})
}
})
.catch((error) => {
.catch(() => {
this.hasFields = false;
});

View File

@ -7,8 +7,8 @@
autocomplete
:loading="loading"
field="label"
@typing="search">
</b-taginput>
@typing="search"/>
</div>
</template>
@ -18,8 +18,8 @@
export default {
created(){
let collectionId = ( this.field && this.field.field.field_type_options.collection_id ) ? this.field.field.field_type_options.collection_id : this.collection_id;
if( this.field.value ){
let collectionId = ( this.field && this.field.field.field_type_options.collection_id ) ? this.field.field.field_type_options.collection_id : this.collection_id;
let query = qs.stringify({ postin: ( Array.isArray( this.field.value ) ) ? this.field.value : [ this.field.value ] });
axios.get('/collection/'+collectionId+'/items?' + query)
@ -29,7 +29,21 @@
}
})
.catch(error => {
console.log(error);
this.$console.log(error);
});
}
if( this.field.field.field_type_options
&& this.field.field.field_type_options.search.length > 0){
axios.get('/collection/'+ collectionId +'/fields?context=edit')
.then( res => {
for (let item of res.data) {
if( this.field.field.field_type_options.search.indexOf( item.id ) >= 0 )
this.searchFields.push( item );
}
})
.catch(error => {
this.$console.log(error);
});
}
},
@ -40,7 +54,10 @@
options: [],
loading: false,
collectionId: 0,
inputValue: null
inputValue: null,
searchFields: [],
queryObject: {},
itemsFound: []
}
},
props: {
@ -80,28 +97,43 @@
}
if (query !== '') {
let metaquery = this.mountQuery( query );
this.loading = true;
this.options = [];
let collectionId = ( this.field && this.field.field.field_type_options.collection_id ) ? this.field.field.field_type_options.collection_id : this.collection_id;
axios.get('/collection/'+collectionId+'/items')
axios.get('/collection/'+collectionId+'/items?' + qs.stringify( metaquery ))
.then( res => {
let result = [];
this.loading = false;
result = res.data.filter(item => {
return item.title.toLowerCase()
.indexOf(query.toLowerCase()) > -1;
});
let result = res.data;
for (let item of result) {
this.options.push({ label: item.title, value: item.id })
}
})
.catch(error => {
console.log(error);
this.$console.log(error);
});
} else {
this.options = [];
}
},
mountQuery( search ){
let query = []
if( this.searchFields.length > 0){
query['metaquery'] = [];
const metaquery = query['metaquery'];
metaquery['relation'] = 'OR'
for( let index in this.searchFields ){
metaquery[index] = {
key: this.searchFields[index].id,
value: search
}
}
query['metaquery'] = metaquery;
} else {
query['search'] = search;
}
return query;
}
}
}

View File

@ -1,24 +1,22 @@
<template>
<section
:listen="setError">
<b-field :addons="false"
:type="optionType"
:message="optionMessage"
>
<b-field
:addons="false"
:type="optionType"
:message="optionMessage">
<label class="label">
{{ $i18n.getHelperTitle('tainacan-selectbox', 'options') }}<span :class="optionType" >&nbsp;*&nbsp;</span>
<help-button
:title="$i18n.getHelperTitle('tainacan-selectbox', 'options')"
:message="$i18n.getHelperMessage('tainacan-selectbox', 'options')">
</help-button>
:message="$i18n.getHelperMessage('tainacan-selectbox', 'options')"/>
</label>
<b-taginput
v-model="options"
@input="emitValues()"
@focus="clear()"
icon="label"
:placeholder="$i18n.get('new')">
</b-taginput>
:placeholder="$i18n.get('new')"/>
</b-field>
</section>
</template>
@ -45,12 +43,11 @@
computed: {
setError(){
if( this.errors && this.errors.options !== '' ){
this.optionType = 'is-danger';
this.optionMessage = this.errors.options;
this.setErrorsAttributes( 'is-danger', this.errors.options )
} else {
this.optionType = '';
this.optionMessage = '';
this.setErrorsAttributes( '', '' )
}
return true;
}
},
methods: {
@ -62,6 +59,10 @@
this.$emit('input',{
options: ( this.options.length > 0 ) ? this.options.join('\n') : ''
})
},
setErrorsAttributes( type, message ){
this.optionType = type;
this.optionMessage = message;
}
}
}

View File

@ -5,7 +5,7 @@
v-model="selected"
@input="onChecked()">
<option
v-for="option,index in getOptions"
v-for="(option, index) in getOptions"
:key="index"
:label="option"
:value="option"

View File

@ -1,29 +1,49 @@
<template>
<b-field
:addons="false"
<b-field
:addons="false"
:label="field.field.name"
:message="getErrorMessage"
:type="fieldTypeMessage">
<help-button
<help-button
:title="field.field.name"
:message="field.field.description">
</help-button>
<div v-if="isTextInputComponent( field.field.field_type_object.component )">
<component :id="field.field.field_type_object.component + '-' + field.field.slug" :is="field.field.field_type_object.component" v-model="inputs[0]" :field="field" @blur="changeValue()"></component>
<div v-if="field.field.multiple == 'yes'">
<div v-if="index > 0" v-for="(input, index) in inputsList " v-bind:key="index" class="multiple-inputs">
<component :id="field.field.field_type_object.component + '-' + field.field.slug" :is="field.field.field_type_object.component" v-model="inputs[index]" :field="field" @blur="changeValue()"></component><a class="button" v-if="index > 0" @click="removeInput(index)">-</a>
</div>
<a class="button" @click="addInput">+</a>
:message="field.field.description"/>
<div v-if="isTextInputComponent( field.field.field_type_object.component )">
<component
:id="field.field.field_type_object.component + '-' + field.field.slug"
:is="field.field.field_type_object.component"
v-model="inputs[0]"
:field="field"
@blur="changeValue()"/>
<div v-if="field.field.multiple == 'yes'">
<div
v-if="index > 0"
v-for="(input, index) in inputsList "
:key="index"
class="multiple-inputs">
<component
:id="field.field.field_type_object.component + '-' + field.field.slug"
:is="field.field.field_type_object.component"
v-model="inputs[index]"
:field="field"
@blur="changeValue()"/><a
class="button"
v-if="index > 0"
@click="removeInput(index)">-</a>
</div>
<a
class="button"
@click="addInput">+</a>
</div>
<div v-else>
<component
:id="field.field.field_type_object.component + '-' + field.field.slug"
:is="field.field.field_type_object.component" v-model="inputs"
:field="field" @blur="changeValue()"></component>
</div>
</b-field>
</div>
<div v-else>
<component
:id="field.field.field_type_object.component + '-' + field.field.slug"
:is="field.field.field_type_object.component"
v-model="inputs"
:field="field"
@blur="changeValue()"/>
</div>
</b-field>
</template>
<script>
@ -32,7 +52,9 @@
export default {
name: 'TainacanFormItem',
props: {
field: {}
field: {
type: Object
}
},
data(){
return {
@ -48,12 +70,12 @@
let msg = '';
let errors = eventBus.getErrors(this.field.field.id);
if ( errors) {
this.fieldTypeMessage = 'is-danger';
this.setFieldTypeMessage('is-danger');
for (let index in errors) {
msg += errors[index] + '\n';
}
} else {
this.fieldTypeMessage = '';
this.setFieldTypeMessage('');
}
return msg;
}
@ -85,6 +107,9 @@
isTextInputComponent( component ){
let array = ['tainacan-relationship','tainacan-category'];
return !( array.indexOf( component ) >= 0 );
},
setFieldTypeMessage( message ){
this.fieldTypeMessage = message;
}
}
}

View File

@ -1,9 +1,9 @@
<template>
<b-input
:id="id"
:value="inputValue"
@blur="onBlur"
@input="onInput($event)"></b-input>
:id="id"
:value="inputValue"
@blur="onBlur"
@input="onInput($event)"/>
</template>
<script>
@ -33,9 +33,6 @@
this.inputValue = $event;
this.$emit('input', this.inputValue);
}
},
created(){
this.inputValue = this.value;
}
}
</script>

View File

@ -4,7 +4,7 @@
type="textarea"
:value="inputValue"
@blur="onBlur"
@input="onInput($event)"></b-input>
@input="onInput($event)"/>
</template>
<script>
@ -34,9 +34,6 @@
this.inputValue = $event;
this.$emit('input', this.inputValue);
}
},
created(){
this.inputValue = this.value;
}
}
</script>

View File

@ -12,8 +12,12 @@
@select="option => setResults(option) ">
<template slot-scope="props">
<div class="media">
<div class="media-left" v-if="props.option.img">
<img width="32" :src="`${props.option.img}`">
<div
class="media-left"
v-if="props.option.img">
<img
width="32"
:src="`${props.option.img}`">
</div>
<div class="media-content">
{{ props.option.label }}
@ -23,11 +27,12 @@
</b-autocomplete>
<br>
<div class="field has-text-centered">
<b-tag v-if="results !== ''"
type="is-primary"
size="is-small"
closable
@close="clearSearch()">
<b-tag
v-if="results !== ''"
type="is-primary"
size="is-small"
closable
@close="clearSearch()">
{{ results }}
</b-tag>
</div>
@ -37,6 +42,7 @@
<script>
import { tainacan as axios } from '../../../js/axios/axios'
import { filter_type_mixin } from '../filter-types-mixin'
import qs from 'qs';
export default {
created(){
@ -53,7 +59,7 @@
}
})
.catch(error => {
console.log(error);
this.$console.log(error);
});
},
data(){
@ -95,10 +101,10 @@
promise = this.getValuesPlainText( this.field, query );
}
promise.then( data => {
promise.then( () => {
this.isLoading = false;
}).catch( error => {
console.log('error select', error );
this.$console.log('error select', error );
this.isLoading = false;
});
},
@ -121,12 +127,12 @@
.then( res => {
for (let item of res.data) {
// instance.selected.push({ label: item.title, value: item.id, img: '' });
console.log(item.title);
this.$console.log(item.title);
instance.results = item.title;
}
})
.catch(error => {
console.log(error);
this.$console.log(error);
});
} else {
instance.results = metadata.value;

View File

@ -1,7 +1,7 @@
<template>
<div class="block">
<div
v-for="option,index in options"
v-for="(option, index) in options"
:key="index"
class="field">
<b-checkbox
@ -31,7 +31,7 @@
}
})
.catch(error => {
console.log(error);
this.$console.log(error);
});
},
data(){
@ -57,7 +57,7 @@
let promise = null;
this.isLoading = true;
if ( this.type === 'Tainacan\Field_types\Relationship' ) {
if ( this.type === 'Tainacan\\Field_types\\Relationship' ) {
let collectionTarget = ( this.filter && this.filter.field.field_type_options.collection_id ) ?
this.filter.field.field_type_options.collection_id : this.collection_id;
@ -67,12 +67,12 @@
promise = this.getValuesPlainText( this.field );
}
promise.then( data => {
promise.then(() => {
this.isLoading = false;
this.selectedValues()
})
.catch( error => {
console.log('error select', error );
this.$console.log('error select', error );
this.isLoading = false;
});
},

View File

@ -5,37 +5,36 @@
size="is-small"
v-model="date_init"
@input="validate_values()"
icon="calendar-today">
</b-datepicker>
icon="calendar-today"/>
<br>
<b-datepicker
size="is-small"
v-model="date_end"
@input="validate_values()"
@focus="isTouched = true"
icon="calendar-today">
</b-datepicker>
icon="calendar-today"/>
<br>
</div>
<div class="columns" v-else>
<div
class="columns"
v-else>
<b-input
size="is-small"
type="number"
@input="validate_values()"
class="column"
v-model="value_init">
</b-input>
v-model="value_init"/>
<b-input
size="is-small"
type="number"
@input="validate_values()"
@focus="isTouched = true"
class="column"
v-model="value_end">
</b-input>
v-model="value_end"/>
</div>
<div class="field has-text-centered">
<b-tag v-if="isValid && !clear"
<b-tag
v-if="isValid && !clear"
type="is-primary"
size="is-small"
closable
@ -66,7 +65,7 @@
}
})
.catch(error => {
console.log(error);
this.$console.log(error);
});
},
data(){
@ -91,7 +90,7 @@
field_id: [Number], // not required, but overrides the filter field id if is set
collection_id: [Number], // not required, but overrides the filter field id if is set
id: '',
query: {}
query: Object
},
methods: {
// only validate if the first value is higher than first

View File

@ -8,7 +8,7 @@
expanded>
<option value="">{{ $i18n.get('label_selectbox_init') }}...</option>
<option
v-for="option,index in options"
v-for="(option, index) in options"
:key="index"
:label="option.label"
:value="option.value"
@ -36,7 +36,7 @@
}
})
.catch(error => {
console.log(error);
this.$console.log(error);
});
},
data(){
@ -66,12 +66,12 @@
promise = this.getValuesPlainText( this.field );
}
promise.then( data => {
promise.then(() => {
this.isLoading = false;
instance.selectedValues();
})
.catch( error => {
console.log('error select', error );
this.$console.log('error select', error );
this.isLoading = false;
});
},

View File

@ -9,8 +9,7 @@
autocomplete
:loading="loading"
field="label"
@typing="search">
</b-taginput>
@typing="search"/>
</div>
</template>
@ -34,7 +33,7 @@
}
})
.catch(error => {
console.log(error);
this.$console.log(error);
});
},
data(){
@ -81,10 +80,10 @@
promise = this.getValuesPlainText( this.field, query );
}
promise.then( data => {
promise.then(() => {
this.isLoading = false;
}).catch( error => {
console.log('error select', error );
this.$console.log('error select', error );
this.isLoading = false;
});
},
@ -110,7 +109,7 @@
}
})
.catch(error => {
console.log(error);
this.$console.log(error);
});
} else {
for (let item of metadata.value) {

View File

@ -1,29 +1,29 @@
<template>
<b-field :label="filter.name"
:message="getErrorMessage"
:type="filterTypeMessage">
<b-field
:label="filter.name"
:message="getErrorMessage"
:type="filterTypeMessage">
<div>
<component
:id="filter.filter_type_object.component + '-' + filter.slug"
:is="filter.filter_type_object.component"
:filter="getFilter"
:query="query"
@input="listen( $event )"></component>
@input="listen( $event )"/>
</div>
</b-field>
</template>
<script>
import { eventFilterBus } from '../../js/event-bus-filters'
import qs from 'qs';
import { mapActions, mapGetters } from 'vuex';
import router from '../../admin/js/router'
export default {
name: 'TainacanFiltersList',
props: {
filter: {},
query: {}
filter: Object,
query: Object
},
data(){
return {
@ -36,12 +36,12 @@
let msg = '';
let errors = eventFilterBus.getErrors( this.filter.id );
if ( errors) {
this.filterTypeMessage = 'is-danger';
this.setFilterTypeMessage('is-danger');
for (let index in errors) {
msg += errors[index] + '\n';
}
} else {
this.filterTypeMessage = '';
this.setFilterTypeMessage('');
}
return msg;
},
@ -62,6 +62,9 @@
eventFilterBus.$emit( 'input', ( event.field_id ) ? event : event.detail[0] );
router.push({ query: {} });
router.push({ query: this.getPostQuery() });
},
setFilterTypeMessage( message ){
this.filterTypeMessage = message;
}
}
}

View File

@ -243,8 +243,8 @@ class Collections extends Repository {
* @return mixed|Collection
*/
public function delete( $args ) {
if ( ! empty( $args[1] ) && $args[1]['is_permanently'] === true ) {
return new Entities\Collection( wp_delete_post( $args[0], $args[1]['is_permanently'] ) );
if ( ! empty( $args[1] ) && $args[1] === true ) {
return new Entities\Collection( wp_delete_post( $args[0], $args[1] ) );
}
return new Entities\Collection( wp_trash_post( $args[0] ) );

View File

@ -644,6 +644,30 @@ class Fields extends Repository {
// Clear the result cache
$wpdb->flush();
$field = new Entities\Field( $field_id );
// handle core titles
if( strpos( $field->get_field_type(), 'Core') !== false ){
$collection = new Entities\Collection( $collection_id );
$Tainacan_Items = \Tainacan\Repositories\Items::getInstance();
$items = $Tainacan_Items->fetch( [], $collection, 'OBJECT');
$return = [];
foreach ($items as $item) {
if( strpos( $field->get_field_type(), 'Core_Title') !== false ){
$return[] = [ 'item_id' => $item->get_id(), 'field_id' => $field_id, 'mvalue' => $item->get_title() ];
} else {
$return[] = [ 'item_id' => $item->get_id(), 'field_id' => $field_id, 'mvalue' => $item->get_description() ];
}
}
if (!empty($return)) {
$results[] = $return;
}
return $results;
}
$item_post_type = "%%{$collection_id}_item";
$collection = new Entities\Collection($collection_id);

View File

@ -188,8 +188,8 @@ class Filters extends Repository {
*
*/
public function delete($args){
if(!empty($args[1]) && $args[1]['is_permanently'] === true){
return new Entities\Filter(wp_delete_post($args[0], $args[1]['is_permanently']));
if(!empty($args[1]) && $args[1] === true){
return new Entities\Filter(wp_delete_post($args[0], $args[1]));
}
return new Entities\Filter(wp_trash_post($args[0]));

View File

@ -25,6 +25,7 @@ class Items extends Repository {
protected function __construct()
{
parent::__construct();
add_filter( 'posts_where', array(&$this, 'title_in_posts_where'), 10, 2 );
}
public function get_map() {
@ -304,11 +305,32 @@ class Items extends Repository {
* @return mixed|Entities\Item
*/
public function delete( $args ) {
if ( ! empty( $args[1] ) && $args[1]['is_permanently'] === true ) {
return new Entities\Item( wp_delete_post( $args[0], $args[1]['is_permanently'] ) );
if ( ! empty( $args[1] ) && $args[1] === true ) {
return new Entities\Item( wp_delete_post( $args[0], $args[1] ) );
}
return new Entities\Item( wp_trash_post( $args[0] ) );
}
/**
* allow wp query filter post by array of titles
*
* @param $where
* @param $wp_query
* @return string
*/
public function title_in_posts_where( $where, $wp_query ) {
global $wpdb;
if ( $post_title_in = $wp_query->get( 'post_title_in' ) ) {
if(is_array( $post_title_in ) && isset( $post_title_in['value']) ){
$quotes = [];
foreach ($post_title_in['value'] as $title) {
$quotes[] = "'" . esc_sql( $wpdb->esc_like( $title ) ). "'";
}
}
$where .= ' '.$post_title_in['relation'].' ' . $wpdb->posts . '.post_title IN ( ' .implode(',', $quotes ) . ')';
}
return $where;
}
}

View File

@ -209,9 +209,9 @@ class Taxonomies extends Repository {
public function delete($args){
$taxonomy_id = $args[0];
$taxonomy_name = $args[1];
$is_permanently = $args[2]['is_permanently'];
$permanently = $args[2];
if($is_permanently === true){
if($permanently === true){
$unregistered = unregister_taxonomy($taxonomy_name);
if($unregistered instanceof \WP_Error){

View File

@ -93,8 +93,13 @@ class Terms extends Repository {
unset($defaults['id']);
return $defaults;
}
public function insert($term){
/**
* @param Entities\Entity $term
*
* @return Entities\Entity|Entities\Term
*/
public function insert($term){
// First iterate through the native post properties
$map = $this->get_map();
foreach ($map as $prop => $mapped) {
@ -104,22 +109,39 @@ class Terms extends Repository {
}
// save post and get its ID
$term_inserted = wp_insert_term( $term->get_name(), $term->get_taxonomy(), [
'parent' => $term->get_parent(),
'description' => $term->get_description(),
]);
if(isset($term->WP_Term->term_id)){
$args = [];
foreach ($map as $prop => $mapped) {
if ($mapped['map'] != 'termmeta') {
$get_ = 'get_'. $prop;
if( !empty($term->WP_Term->{$mapped['map']}) ){
$args[$mapped['map']] = $term->$get_();
}
}
}
$term_saved = wp_update_term( $term->get_id(), $term->get_taxonomy(), $args);
} else {
$term_saved = wp_insert_term( $term->get_name(), $term->get_taxonomy(), [
'parent' => $term->get_parent(),
'description' => $term->get_description(),
] );
}
// Now run through properties stored as postmeta
foreach ($map as $prop => $mapped) {
if ($mapped['map'] == 'termmeta') {
update_term_meta($term_inserted['term_id'], $prop, wp_slash( $term->get_mapped_property($prop) ));
update_term_meta($term_saved['term_id'], $prop, wp_slash( $term->get_mapped_property($prop) ));
}
}
do_action('tainacan-insert', $term);
do_action('tainacan-insert-Term', $term);
//var_dump($term);
return new Entities\Term($term_inserted['term_id'], $term->get_taxonomy());
return new Entities\Term($term_saved['term_id'], $term->get_taxonomy());
}
/**
@ -178,7 +200,7 @@ class Terms extends Repository {
}
}
public function update($object, $tax_name = null){
public function update($object, $args = null){
return $this->insert($object);
}

View File

@ -6,8 +6,7 @@ import { eventBus } from './event-bus-web-components';
import { eventFilterBus } from './event-bus-filters';
import Buefy from 'buefy'
Vue.use(Buefy)
Vue.use(Buefy);
Vue.use(VueCustomElement);

View File

@ -1,5 +1,6 @@
import axios from '../../../axios/axios'
// CATEGORIES
export const createCategory = ({commit}, category) => {
return new Promise(( resolve, reject ) => {
axios.tainacan.post('/taxonomies', {
@ -25,14 +26,17 @@ export const createCategory = ({commit}, category) => {
export const deleteCategory = ({ commit }, categoryId) => {
return new Promise(( resolve, reject ) => {
axios.tainacan.delete(`/taxonomies/${categoryId}`, {
'is_permanently': true
})
axios.tainacan.delete(`/taxonomies/${categoryId}?permanently=${true}`)
.then(res => {
console.info(res);
resolve( res.data );
commit('deleteCategory', res.data);
resolve( res );
})
.catch(error => {
console.error(error);
reject( error )
});
});
@ -111,4 +115,72 @@ export const fetchCategoryName = ({ commit }, categoryId) => {
reject(error)
})
});
};
};
// CATEGORY TERMS
export const sendTerm = ({commit}, { categoryId, index, name, description, parent }) => {
return new Promise(( resolve, reject ) => {
axios.tainacan.post('/taxonomy/' + categoryId + '/terms/', {
name: name,
description: description,
parent: parent
})
.then( res => {
let term = res.data;
commit('setSingleTerm', term);
resolve( term );
})
.catch(error => {
console.log(error);
reject( error );
});
});
};
export const deleteTerm = ({ commit }, { categoryId, termId }) => {
return new Promise(( resolve, reject ) => {
axios.tainacan.delete(`/taxonomy/${categoryId}/terms/${termId}?permanently=${true}`)
.then(res => {
let term = res.data;
commit('deleteTerm', termId);
resolve( term );
})
.catch(error => {
reject( error )
});
});
};
export const updateTerm = ({ commit }, { categoryId, termId, index, name, description, parent }) => {
return new Promise(( resolve, reject ) => {
axios.tainacan.patch('/taxonomy/' + categoryId + '/terms/' + termId, {
name: name,
description: description,
parent: parent
})
.then( res => {
let term = res.data;
commit('setSingleTerm', term);
resolve( term );
})
.catch(error => {
console.log(error);
reject(error)
//reject({ error_message: error['response']['data'].error_message, errors: error['response']['data'].errors });
});
});
};
export const fetchTerms = ({ commit }, categoryId ) => {
return new Promise((resolve, reject) => {
axios.tainacan.get(`/taxonomy/${categoryId}/terms/?hideempty=0`)
.then(res => {
let terms = res.data;
commit('setTerms', terms);
resolve( terms );
})
.catch(error => {
reject( error );
});
});
};

View File

@ -8,4 +8,8 @@ export const getCategories = state => {
export const getCategoryName = state => {
return state.categoryName;
};
export const getTerms = state => {
return state.terms;
};

View File

@ -6,6 +6,7 @@ const state = {
categories: [],
category: {},
categoryName: String,
terms: []
};
export default {

View File

@ -1,3 +1,4 @@
// CATEGORIES
export const setCategory = (state, category) => {
state.category = category;
};
@ -8,4 +9,34 @@ export const setCategories = (state, categories) => {
export const setCategoryName = (state, name) => {
state.categoryName = name;
};
export const deleteCategory = ( state, category ) => {
let index = state.categories.findIndex(deletedCategory => deletedCategory.id === category.id);
if (index >= 0) {
state.categories.splice(index, 1);
}
};
// CATEGORY 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);
}
};

View File

@ -792,8 +792,8 @@ msgstr ""
#: api/class-tainacan-rest-controller.php:501
msgid ""
"Select taxonomy term by. Possible values are term_id, name, slug or "
"term_taxonomy_id. Default value is term_id."
"Select taxonomy term by. Possible values are id, name, slug or "
"term_taxonomy_id. Default value is id."
msgstr ""
#: api/class-tainacan-rest-controller.php:505

View File

@ -97,13 +97,13 @@ class TAINACAN_REST_Collections_Controller extends TAINACAN_UnitApiTestCase {
$collection1 = $this->tainacan_entity_factory->create_entity('collection', '', true);
// Delete permanently
$delete_permanently = json_encode(['is_permanently' => true]);
$delete_permanently = ['permanently' => true];
$request = new \WP_REST_Request(
'DELETE',
$this->namespace . '/collections/' . $collection1->get_id()
);
$request->set_body($delete_permanently);
$request->set_query_params($delete_permanently);
$response = $this->server->dispatch($request);
@ -122,13 +122,13 @@ class TAINACAN_REST_Collections_Controller extends TAINACAN_UnitApiTestCase {
$collection2 = $this->tainacan_entity_factory->create_entity('collection', '', true);
// Move to trash
$delete_permanently = json_encode(['is_permanently' => false]);
$delete_permanently = ['permanently' => false];
$request = new \WP_REST_Request(
'DELETE',
$this->namespace . '/collections/' . $collection2->get_id()
);
$request->set_body($delete_permanently);
$request->set_query_params($delete_permanently);
$response = $this->server->dispatch($request);

View File

@ -84,14 +84,12 @@ class TAINACAN_REST_Terms_Controller extends TAINACAN_UnitApiTestCase {
true
);
$is_permanently = json_encode([
'is_permanently' => false
]);
$permanently = [ 'permanently' => false ];
$request = new \WP_REST_Request(
'DELETE', $this->namespace . '/filters/' . $filter->get_id());
$request->set_body($is_permanently);
$request->set_query_params($permanently);
$response = $this->server->dispatch($request);
@ -105,14 +103,12 @@ class TAINACAN_REST_Terms_Controller extends TAINACAN_UnitApiTestCase {
##### DELETE #####
$is_permanently = json_encode([
'is_permanently' => true
]);
$permanently = [ 'permanently' => true ];
$request = new \WP_REST_Request(
'DELETE', $this->namespace . '/filters/' . $filter->get_id());
$request->set_body($is_permanently);
$request->set_query_params($permanently);
$response = $this->server->dispatch($request);

View File

@ -93,13 +93,13 @@ class TAINACAN_REST_Items_Controller extends TAINACAN_UnitApiTestCase {
);
// Move to trash
$delete_permanently = json_encode(['is_permanently' => false]);
$delete_permanently = ['permanently' => false];
$request = new \WP_REST_Request(
'DELETE',
$this->namespace . '/items/' . $item1->get_id()
);
$request->set_body($delete_permanently);
$request->set_query_params($delete_permanently);
$response = $this->server->dispatch($request);
@ -126,13 +126,13 @@ class TAINACAN_REST_Items_Controller extends TAINACAN_UnitApiTestCase {
);
// Delete permanently
$delete_permanently = json_encode(['is_permanently' => true]);
$delete_permanently = ['permanently' => true];
$request = new \WP_REST_Request(
'DELETE',
$this->namespace . '/items/' . $item2->get_id()
);
$request->set_body($delete_permanently);
$request->set_query_params($delete_permanently);
$response = $this->server->dispatch($request);

View File

@ -19,13 +19,13 @@ class TAINACAN_REST_Taxonomies_Controller extends TAINACAN_UnitApiTestCase {
true
);
$is_permanently = json_encode(['is_permanently' => false]);
$permanently = [ 'permanently' => false ];
$request_trash = new \WP_REST_Request(
'DELETE', $this->namespace . '/taxonomies/' . $taxonomy->get_id()
);
$request_trash->set_body($is_permanently);
$request_trash->set_query_params($permanently);
$this->server->dispatch($request_trash);
@ -36,13 +36,13 @@ class TAINACAN_REST_Taxonomies_Controller extends TAINACAN_UnitApiTestCase {
################ DELETE ###
$is_permanently = json_encode(['is_permanently' => true]);
$permanently = [ 'permanently' => true ];
$request_delete = new \WP_REST_Request(
'DELETE', $this->namespace . '/taxonomies/' . $taxonomy->get_id()
);
$request_delete->set_body($is_permanently);
$request_delete->set_query_params($permanently);
$this->server->dispatch($request_delete);
@ -122,8 +122,10 @@ class TAINACAN_REST_Taxonomies_Controller extends TAINACAN_UnitApiTestCase {
$data = $response->get_data();
$this->assertEquals($taxonomy1->get_name(), $data[1]['name']);
$this->assertEquals($taxonomy2->get_name(), $data[0]['name']);
$names = [ $data[1]['name'], $data[0]['name']];
$this->assertContains($taxonomy1->get_name(), $names);
$this->assertContains($taxonomy2->get_name(), $names);
}
public function test_update_taxonomy(){

View File

@ -97,7 +97,8 @@ class TAINACAN_REST_Terms extends TAINACAN_UnitApiTestCase {
);
$new_attributes = json_encode([
'name' => 'Trap'
'name' => 'Trap',
'user' => 7
]);
$request = new \WP_REST_Request(
@ -112,6 +113,7 @@ class TAINACAN_REST_Terms extends TAINACAN_UnitApiTestCase {
$this->assertNotEquals('Rock', $data['name']);
$this->assertEquals('Trap', $data['name']);
$this->assertEquals(7, $data['user']);
$this->assertEquals($taxonomy->get_db_identifier(), $data['taxonomy']);
}

View File

@ -1,5 +1,6 @@
var path = require('path')
var webpack = require('webpack')
let path = require('path');
let webpack = require('webpack');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
entry: {
@ -14,6 +15,15 @@ module.exports = {
devtool: 'eval-source-map',
module: {
rules: [
{
enforce: "pre",
test: /\.vue$/,
exclude: /node_modules/,
loader: "eslint-loader",
options: {
fix: false,
},
},
{
test: /\.vue$/,
loader: 'vue-loader',
@ -46,14 +56,20 @@ module.exports = {
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.js'
'vue$': 'vue/dist/vue.esm.js'
}
},
devServer: {
historyApiFallback: true,
noInfo: true
},
}
node: {
fs: 'empty'
},
performance: {
hints: false
},
};
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = 'inline-source-map';
@ -64,10 +80,9 @@ if (process.env.NODE_ENV === 'production') {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
new UglifyJsPlugin({
parallel: true,
sourceMap: true,
}),
new webpack.LoaderOptionsPlugin({
minimize: true