Merge branch 'develop' into full-screen

This commit is contained in:
Mateus Machado Luna 2018-09-26 10:47:14 -03:00
commit 5080c3b9e6
56 changed files with 1733 additions and 1077 deletions

1715
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@
},
"dependencies": {
"axios": "^0.18.0",
"buefy": "^0.6.6",
"buefy": "^0.6.7",
"bulma": "^0.7.1",
"mdi": "^2.2.43",
"moment": "^2.22.2",
@ -26,26 +26,26 @@
"vuex": "^3.0.1"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/core": "^7.1.0",
"@babel/preset-env": "^7.1.0",
"autoprefixer": "^9.1.5",
"babel-loader": "^8.0.2",
"cross-env": "^5.2.0",
"css-loader": "^1.0.0",
"element-theme-chalk": "^2.4.6",
"eslint": "^5.5.0",
"element-theme-chalk": "^2.4.7",
"eslint": "^5.6.0",
"eslint-loader": "^2.1.0",
"eslint-plugin-vue": "^4.7.1",
"file-loader": "^2.0.0",
"postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.0",
"uglifyjs-webpack-plugin": "^1.3.0",
"uglifyjs-webpack-plugin": "^2.0.1",
"vue-custom-element": "^3.2.5",
"vue-loader": "^15.4.1",
"vue-loader": "^15.4.2",
"vue-template-compiler": "^2.5.17",
"webpack": "^4.17.2",
"webpack": "^4.19.1",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.7"
"webpack-dev-server": "^3.1.8"
}
}

View File

@ -1,7 +1,7 @@
<template>
<div>
<section
style="position: relative;"
:style="{ position: relative }"
v-if="!metadata || metadata.length <= 0"
class="field is-grouped-centered section">
<b-loading
@ -646,6 +646,10 @@
@import '../../scss/_variables.scss';
.loading-overlay {
min-height: 200px;
}
.padding-in-header {
padding-right: 3.3%;
padding-left: 3.7%;

View File

@ -8,7 +8,16 @@
@click="isMetadataColumnCompressed = !isMetadataColumnCompressed">
<b-icon :icon="isMetadataColumnCompressed ? 'menu-left' : 'menu-right'" />
</button>
<tainacan-title />
<div class="tainacan-page-title">
<h1 v-if="isCreatingNewItem">{{ $i18n.get('title_create_item_collection') + ' ' }}<span style="font-weight: 600;">{{ collectionName }}</span></h1>
<h1 v-else>{{ $i18n.get('title_edit_item') + ' ' }}<span style="font-weight: 600;">{{ (item != null && item != undefined) ? item.title : '' }}</span></h1>
<a
@click="$router.go(-1)"
class="back-link has-text-secondary">
{{ $i18n.get('back') }}
</a>
<hr>
</div>
<form
v-if="!isLoading"
class="tainacan-form"
@ -489,8 +498,9 @@ export default {
return {
pageTitle: '',
itemId: Number,
item: null,
item: {},
collectionId: Number,
isCreatingNewItem: false,
isLoading: false,
isMetadataColumnCompressed: false,
metadatumCollapses: [],
@ -837,6 +847,7 @@ export default {
this.form.collectionId = this.collectionId;
if (this.$route.fullPath.split("/").pop() == "new") {
this.isCreatingNewItem = true;
this.createNewItem();
} else if (this.$route.fullPath.split("/").pop() == "edit") {
this.isLoading = true;
@ -962,8 +973,33 @@ export default {
}
.tainacan-page-title {
padding-left: $page-side-padding;
padding-right: $page-side-padding;
padding: 0 $page-side-padding;
margin-bottom: 40px;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: space-between;
h1, h2 {
font-size: 20px;
font-weight: 500;
color: $gray5;
display: inline-block;
width: 80%;
flex-shrink: 1;
flex-grow: 1;
}
a.back-link{
font-weight: 500;
float: right;
margin-top: 5px;
}
hr{
margin: 3px 0px 4px 0px;
height: 1px;
background-color: $secondary;
width: 100%;
}
}
.column.is-5-5 {

View File

@ -107,7 +107,7 @@
placement: 'auto-start'
}">
<span :class="{'occluding-content': bgProcess.progress_value }">{{ bgProcess.progress_label ? bgProcess.progress_label : $i18n.get('label_no_details_of_process') }}</span>
<span>{{ bgProcess.progress_value ? ' (' + bgProcess.progress_value + '%)' : '' }}</span>
<span>{{ bgProcess.progress_value &lt;&equals; 0 ? `(0%)` : ' ('+ bgProcess.progress_value +'%)' }}</span>
</p>
</td>
<!-- Queued on -->
@ -162,18 +162,17 @@
class="icon has-text-success loading-icon">
<div class="control has-icons-right is-loading is-clearfix" />
</span>
<!-- <span
v-if="bgProcess.done <= 0"
class="icon has-text-gray action-icon"
@click="pauseProcess(index)">
<i class="mdi mdi-18px mdi-pause-circle"/>
</span>
<span
v-tooltip="{
content: $i18n.get('label_stop_process'),
autoHide: false,
placement: 'auto-start'
}"
v-if="bgProcess.done <= 0"
class="icon has-text-gray action-icon"
@click="pauseProcess(index)">
<i class="mdi mdi-18px mdi-close-circle-outline"/>
</span> -->
<i class="mdi mdi-18px mdi-stop-circle"/>
</span>
<span
v-tooltip="{
content: $i18n.get('label_process_completed'),
@ -206,6 +205,7 @@
<script>
import { mapActions } from 'vuex';
import CustomDialog from '../other/custom-dialog.vue';
import moment from 'moment'
export default {
name: 'List',
@ -214,7 +214,8 @@
selected: [],
allOnPageSelected: false,
isSelecting: false,
highlightedProcess: ''
highlightedProcess: '',
dateFormat: '',
}
},
props: {
@ -246,7 +247,8 @@
},
methods: {
...mapActions('bgprocess', [
'deleteProcess'
'deleteProcess',
'updateProcess'
]),
selectAllOnPage() {
for (let i = 0; i < this.selected.length; i++)
@ -327,17 +329,26 @@
});
},
getDate(rawDate) {
let date = new Date(rawDate);
let date = moment(rawDate).format(this.dateFormat);
if (date instanceof Date && !isNaN(date))
return date.toLocaleString();
else
if (date != 'Invalid date') {
return date;
} else {
return this.$i18n.get('info_unknown_date');
}
},
pauseProcess() {
pauseProcess(index) {
this.updateProcess({ id: this.processes[index].ID, status: 'closed' });
}
},
mounted() {
let locale = navigator.language;
moment.locale(locale);
let localeData = moment.localeData();
this.dateFormat = localeData.longDateFormat('lll');
if (this.$route.query.highlight) {
this.highlightedProcess = this.$route.query.highlight;
}

View File

@ -1,7 +1,8 @@
<template>
<div class="tainacan-modal-content">
<header class="tainacan-modal-title">
<h2>{{ this.$i18n.get('filter') }} <em>{{ filter.name }}</em></h2>
<h2 v-if="isFilter">{{ this.$i18n.get('filter') }} <em>{{ filter.name }}</em></h2>
<h2 v-else>{{ this.$i18n.get('metadatum') }} <em>{{ metadatum.name }}</em></h2>
<hr>
</header>
<div class="tainacan-form">
@ -76,10 +77,17 @@
:ref="`${key}.${index}-tainacan-li-checkbox-model`"
:key="index">
<b-checkbox
v-if="isCheckbox"
v-model="selected"
:native-value="option.value">
{{ `${option.label}` }}
</b-checkbox>
<b-radio
v-else
v-model="selected"
:native-value="option.value">
{{ `${option.label}` }}
</b-radio>
<a
v-if="option.total_children > 0"
@click="getOptionChildren(option, key, index)">
@ -119,10 +127,17 @@
v-for="(option, key) in searchResults"
:key="key">
<b-checkbox
v-if="isCheckbox"
v-model="selected"
:native-value="option.id ? option.id : option.value">
{{ `${ option.name ? limitChars(option.name) : limitChars(option.label) }` }}
</b-checkbox>
<b-radio
v-else
v-model="selected"
:native-value="option.id ? option.id : option.value">
{{ `${ option.name ? limitChars(option.name) : limitChars(option.label) }` }}
</b-radio>
</li>
<b-loading
:is-full-page="false"
@ -152,24 +167,36 @@
<script>
import qs from 'qs';
import {tainacan as axios} from '../../../js/axios/axios';
import { tainacan as axios } from '../../../js/axios/axios';
import { filter_type_mixin } from '../../../classes/filter-types/filter-types-mixin';
export default {
name: 'CheckboxFilterModal',
mixins: [ filter_type_mixin ],
props: {
isFilter: {
type: Boolean,
default: true
},
filter: '',
parent: Number,
taxonomy_id: Number,
taxonomy: String,
collection_id: Number,
metadatum_id: Number,
metadatum: Object,
selected: Array,
isTaxonomy: false,
isTaxonomy: {
type: Boolean,
default: false,
},
metadatum_type: String,
metadatum_object: Object,
isRepositoryLevel: Boolean,
isCheckbox: {
type: Boolean,
default: true,
},
},
data() {
return {
@ -285,7 +312,13 @@
let query = `?hideempty=0&order=asc&number=${this.maxNumSearchResultsShow}&searchterm=${this.optionName}&` + qs.stringify(query_items);
axios.get(`/collection/${this.collection_id}/facets/${this.metadatum_id}${query}`)
let route = `/collection/${this.collection_id}/facets/${this.metadatum_id}${query}`;
if(this.collection_id == 'default' || this.collection_id == 'filter_in_repository'){
route = `/facets/${this.metadatum_id}${query}`
}
axios.get(route)
.then((res) => {
this.searchResults = res.data;
this.isSearchingLoading = false;
@ -398,7 +431,13 @@
this.isColumnLoading = true;
axios.get(`/collection/${this.collection_id}/facets/${this.metadatum_id}${query}`)
let route = `/collection/${this.collection_id}/facets/${this.metadatum_id}${query}`;
if(this.collection_id == 'default' || this.collection_id == 'filter_in_repository'){
route = `/facets/${this.metadatum_id}${query}`
}
axios.get(route)
.then(res => {
this.removeLevelsAfter(key);
this.createColumn(res, key);
@ -422,7 +461,13 @@
this.isColumnLoading = true;
axios.get(`/collection/${this.collection_id}/facets/${this.metadatum_id}${query}`)
let route = `/collection/${this.collection_id}/facets/${this.metadatum_id}${query}`;
if(this.collection_id == 'default' || this.collection_id == 'filter_in_repository'){
route = `/facets/${this.metadatum_id}${query}`
}
axios.get(route)
.then(res => {
this.appendMore(res.data, key);
@ -438,7 +483,7 @@
applyFilter() {
this.$parent.close();
if(this.isTaxonomy){
if(this.isTaxonomy && this.isFilter){
this.$eventBusSearch.$emit('input', {
filter: 'checkbox',
taxonomy: this.taxonomy,
@ -447,7 +492,7 @@
collection_id: this.collection_id,
terms: this.selected
});
} else {
} else if(this.isFilter) {
this.$eventBusSearch.$emit('input', {
filter: 'checkbox',
compare: 'IN',
@ -455,6 +500,8 @@
collection_id: this.collection_id ? this.collection_id : this.filter.collection_id,
value: this.selected,
});
} else {
this.$emit('input', this.selected)
}
this.$emit('appliedCheckBoxModal');
@ -534,7 +581,7 @@
flex-shrink: 1;
max-width: calc(50% - 8.3333333%);
.b-checkbox {
.b-checkbox, .b-radio {
max-width: 86%;
margin-right: 10px;
}
@ -548,7 +595,7 @@
display: flex;
padding: 0;
.b-checkbox {
.b-checkbox, .b-radio {
max-width: 86%;
margin-left: 0.7rem;
height: 24px;
@ -565,7 +612,7 @@
flex-shrink: 1;
max-width: calc(50% - 8.3333333%);
.b-checkbox {
.b-checkbox, .b-radio {
margin-right: 10px;
}

View File

@ -47,22 +47,22 @@
<span class="icon has-text-gray">
<i
class="mdi mdi-18px"
:class="{ 'mdi-menu-down': processesColapses[index], 'mdi-menu-right': !processesColapses[index] }" />
:class="{ 'mdi-menu-down': processesCollapses[index], 'mdi-menu-right': !processesCollapses[index] }" />
</span>
<p>{{ bgProcess.name ? bgProcess.name : $i18n.get('label_unamed_process') }}</p>
</div>
<!-- <span
v-if="bgProcess.done <= 0"
v-if="bgProcess.done <= 0 && bgProcess.status == 'closed'"
class="icon has-text-gray action-icon"
@click="pauseProcess(index)">
<i class="mdi mdi-18px mdi-pause-circle"/>
</span>
@click="resumeProcess(index)">
<i class="mdi mdi-18px mdi-play-circle"/>
</span> -->
<span
v-if="bgProcess.done <= 0"
class="icon has-text-gray action-icon"
@click="pauseProcess(index)">
<i class="mdi mdi-18px mdi-close-circle-outline"/>
</span> -->
<i class="mdi mdi-18px mdi-stop-circle"/>
</span>
<span
v-if="bgProcess.done > 0 && !bgProcess.error_log"
class="icon has-text-success">
@ -76,14 +76,20 @@
<span
v-if="bgProcess.done <= 0"
class="icon has-text-success loading-icon">
<!--<progress-->
<!--:value="bgProcess.progress_value > 0 ? bgProcess.progress_value : 0"-->
<!--max="100"-->
<!--class="progress is-success is-small is-loading">-->
<!--{{ `(${ bgProcess.progress_value &lt;&equals; 0 ? 0 : bgProcess.progress_value }%)` }}-->
<!--</progress>-->
<div class="control has-icons-right is-loading is-clearfix" />
</span>
</div>
<div
v-if="processesColapses[index]"
v-if="processesCollapses[index]"
class="process-label">
{{ bgProcess.progress_label ? bgProcess.progress_label : $i18n.get('label_no_details_of_process') }}
<span class="process-label-value">{{ (bgProcesses[0].progress_value && bgProcesses[0].progress_value >= 0) ? '(' + bgProcesses[0].progress_value + '%)' : '' }}</span>
<span class="process-label-value">{{ (bgProcess.progress_value && bgProcess.progress_value >= 0) ? '(' + bgProcess.progress_value + '%)' : '' }}</span>
<br>
{{ $i18n.get('label_queued_on') + ' ' + getDate(bgProcess.queued_on) }}
<br>
@ -110,7 +116,7 @@
class="icon has-text-blue5"><i class="mdi mdi-18px mdi-autorenew"/></span>
<p class="footer-title">
{{ hasAnyProcessExecuting ?
(bgProcesses[0].progress_label ? bgProcesses[0].progress_label + ((bgProcesses[0].progress_value && bgProcesses[0].progress_value >= 0) ? ' - ' + bgProcesses[0].progress_value + '%' : '') : $i18n.get('label_no_details_of_process')):
(bgProcesses[0].progress_label ? bgProcesses[0].progress_label + ((bgProcesses[0].progress_value && bgProcesses[0].progress_value >= 0) ? ' - ' + bgProcesses[0].progress_value + '%' : '') : $i18n.get('label_no_details_of_process')):
$i18n.get('info_no_process')
}}
</p>
@ -121,26 +127,22 @@
<script>
import { mapGetters, mapActions } from 'vuex';
import moment from 'moment';
export default {
name: 'ProcessesPopup',
data() {
return {
showProcessesList: false,
processesColapses: [],
hasAnyProcessExecuting: false
processesCollapses: [],
hasAnyProcessExecuting: false,
dateFormat: '',
intervalID: null,
}
},
watch: {
bgProcesses() {
this.processesColapses = [];
this.hasAnyProcessExecuting = false;
for (let i = 0; i < this.bgProcesses.length; i++) {
this.$set(this.processesColapses, i , false);
if (this.bgProcesses[i].done <= 0)
this.hasAnyProcessExecuting = true;
}
bgProcesses(newBG) {
this.hasAnyProcessExecuting = newBG.some((element) => element.done <= 0);
}
},
computed: {
@ -150,35 +152,58 @@ export default {
},
methods: {
...mapActions('bgprocess', [
'fetchProcesses'
'fetchProcesses',
'updateProcess'
]),
...mapGetters('bgprocess', [
'getProcesses',
]),
toggleDetails(index) {
this.$set(this.processesColapses, index, !this.processesColapses[index]);
this.$set(this.processesCollapses, index, !this.processesCollapses[index]);
},
getUnfinishedProcesses() {
let nUnfinishedProcesses = 0
let nUnfinishedProcesses = 0;
for(let i = 0; i < this.bgProcesses.length; i++) {
if (this.bgProcesses[i].done <= 0)
if (this.bgProcesses[i].done <= 0){
nUnfinishedProcesses++;
}
}
return nUnfinishedProcesses;
},
getDate(rawDate) {
let date = new Date(rawDate);
let date = moment(rawDate).format(this.dateFormat);
if (date instanceof Date && !isNaN(date))
return date.toLocaleString();
else
if (date != 'Invalid date') {
return date;
} else {
return this.$i18n.get('info_unknown_date');
}
},
pauseProcess(index) {
this.updateProcess({ id: this.bgProcesses[index].ID, status: 'closed' });
},
pauseProcess() {
}
},
mounted() {
this.fetchProcesses({ page: 1, processesPerPage: 12 });
created() {
let locale = navigator.language;
moment.locale(locale);
let localeData = moment.localeData();
this.dateFormat = localeData.longDateFormat('lll');
this.intervalID = setInterval(() => {
this.fetchProcesses({
page: 1,
processesPerPage: 12
}).then(() => {
if (this.getUnfinishedProcesses() > 0) {
clearInterval(this.intervalID);
}
});
}, 20000);
this.showProcessesList = false;
}
}
@ -299,9 +324,9 @@ export default {
opacity: 1;
cursor: pointer;
}
.loading-icon {
display: none;
}
/*.loading-icon {*/
/*display: none;*/
/*}*/
.process-item>.process-title .mdi-menu-left, .process-item>.process-title .mdi-menu-right {
color: $gray3 !important;
}

View File

@ -30,7 +30,6 @@ import FilterTaginput from '../../classes/filter-types/taginput/Taginput.vue';
import FilterTaxonomyCheckbox from '../../classes/filter-types/taxonomy/Checkbox.vue';
import FilterTaxonomyTaginput from '../../classes/filter-types/taxonomy/Taginput.vue';
import FilterTaxonomySelectbox from '../../classes/filter-types/taxonomy/Selectbox.vue';
import TainacanFormItem from '../../classes/metadata-types/tainacan-form-item.vue';
import TainacanFiltersList from '../../classes/filter-types/tainacan-filter-item.vue';
@ -82,7 +81,6 @@ Vue.component('tainacan-filter-checkbox', FilterCheckbox);
Vue.component('tainacan-filter-taginput', FilterTaginput);
Vue.component('tainacan-filter-taxonomy-checkbox', FilterTaxonomyCheckbox);
Vue.component('tainacan-filter-taxonomy-taginput', FilterTaxonomyTaginput);
Vue.component('tainacan-filter-taxonomy-selectbox', FilterTaxonomySelectbox);
/* Others */
Vue.component('help-button', HelpButton);

View File

@ -26,7 +26,6 @@ import FilterTaginput from '../../classes/filter-types/taginput/Taginput.vue';
import FilterTaxonomyCheckbox from '../../classes/filter-types/taxonomy/Checkbox.vue';
import FilterTaxonomyTaginput from '../../classes/filter-types/taxonomy/Taginput.vue';
import FilterTaxonomySelectbox from '../../classes/filter-types/taxonomy/Selectbox.vue';
import TaincanFormItem from '../../classes/metadata-types/tainacan-form-item.vue';
import TaincanFiltersList from '../../classes/filter-types/tainacan-filter-item.vue';
@ -79,7 +78,6 @@ Vue.component('tainacan-filter-checkbox', FilterCheckbox);
Vue.component('tainacan-filter-taginput', FilterTaginput);
Vue.component('tainacan-filter-taxonomy-checkbox', FilterTaxonomyCheckbox);
Vue.component('tainacan-filter-taxonomy-taginput', FilterTaxonomyTaginput);
Vue.component('tainacan-filter-taxonomy-selectbox', FilterTaxonomySelectbox);
/* Others */
Vue.component('help-button', HelpButton);

View File

@ -111,8 +111,8 @@ UserPrefsPlugin.install = function (Vue, options = {}) {
slug: 'creation_date',
name: 'Creation Date'
},
'view_mode': 'cards',
'admin_view_mode': 'table',
'view_mode': undefined,
'admin_view_mode': 'cards',
'fetch_only': {
0: 'thumbnail',
1: 'creation_date',

View File

@ -68,8 +68,8 @@ export default {
id: null
}
this.params.flex_width = 0;
this.params.flex_height = 0;
this.params.flex_width = 1;
this.params.flex_height = 1;
this.params.width = 220;
this.params.height = 220;

View File

@ -1342,6 +1342,10 @@
cursor: pointer;
transition: top 0.3s;
&:focus {
outline: none !important;
}
.icon {
margin-top: -1px;
}

View File

@ -1156,7 +1156,7 @@
} else {
let prefsAdminViewMode = !this.isRepositoryLevel ? 'admin_view_mode_' + this.collectionId : 'admin_view_mode';
if (this.$userPrefs.get(prefsAdminViewMode) == undefined)
this.$eventBusSearch.setInitialAdminViewMode('table');
this.$eventBusSearch.setInitialAdminViewMode('cards');
else {
let existingViewMode = this.$userPrefs.get(prefsAdminViewMode);
if (existingViewMode == 'cards' ||
@ -1166,7 +1166,7 @@
existingViewMode == 'masonry')
this.$eventBusSearch.setInitialAdminViewMode(this.$userPrefs.get(prefsAdminViewMode));
else
this.$eventBusSearch.setInitialAdminViewMode('table');
this.$eventBusSearch.setInitialAdminViewMode('cards');
}
}
@ -1336,6 +1336,10 @@
cursor: pointer;
transition: top 0.3s;
&:focus {
outline: none !important;
}
.icon {
margin-top: -1px;
}

View File

@ -8,7 +8,15 @@
@click="isMetadataColumnCompressed = !isMetadataColumnCompressed">
<b-icon :icon="isMetadataColumnCompressed ? 'menu-left' : 'menu-right'" />
</button>
<tainacan-title/>
<div class="tainacan-page-title">
<h1>{{ $i18n.get('title_item_page') + ' ' }}<span style="font-weight: 600;">{{ (item != null && item != undefined) ? item.title : '' }}</span></h1>
<a
@click="$router.go(-1)"
class="back-link has-text-secondary">
{{ $i18n.get('back') }}
</a>
<hr>
</div>
<div class="tainacan-form">
<div class="columns">
<div class="column is-5-5">
@ -436,7 +444,7 @@
position: absolute;
z-index: 99;
right: 0;
top: 70px;
top: 148px;
max-width: 36px;
height: 36px;
width: 36px;
@ -462,8 +470,33 @@
}
.tainacan-page-title {
padding-left: $page-side-padding;
padding-right: $page-side-padding;
padding: 0 $page-side-padding;
margin-bottom: 40px;
display: flex;
flex-wrap: wrap;
align-items: flex-end;
justify-content: space-between;
h1, h2 {
font-size: 20px;
font-weight: 500;
color: $gray5;
display: inline-block;
width: 80%;
flex-shrink: 1;
flex-grow: 1;
}
a.back-link{
font-weight: 500;
float: right;
margin-top: 5px;
}
hr{
margin: 3px 0px 4px 0px;
height: 1px;
background-color: $secondary;
width: 100%;
}
}
.tainacan-form>.columns {

View File

@ -21,6 +21,7 @@
padding: 6px 0px;
border-radius: 0px !important;
.dropdown-item {
display: block;
text-decoration: none;
padding: 0.375rem 1rem;
font-size: 0.8125rem;

View File

@ -104,6 +104,7 @@
.media {
width: 100%;
display: flex;
.list-metadata {
padding: 0.75rem 1.375rem;

View File

@ -103,6 +103,7 @@
.media {
width: 100%;
display: flex;
.list-metadata {
padding: 25px;

View File

@ -72,6 +72,7 @@ return apply_filters( 'tainacan-admin-i18n', [
'finish' => __( 'Finish', 'tainacan' ),
'select_to_create' => __( 'select to create', 'tainacan' ),
'new_action' => __( 'New action', 'tainacan' ),
'clear_radio' => __( 'Clear selected radio', 'tainacan'),
// Wordpress Status
'publish' => __( 'Publish', 'tainacan' ),
@ -288,6 +289,7 @@ return apply_filters( 'tainacan-admin-i18n', [
'label_last_processed_on' => __( 'Last processed on:', 'tainacan' ),
'label_progress' => __( 'Progress', 'tainacan' ),
'label_process_completed' => __( 'Process completed', 'tainacan' ),
'label_stop_process' => __( 'Stop process', 'tainacan' ),
'label_process_failed' => __( 'Process failed', 'tainacan' ),
'label_max_options_to_show' => __( 'Max options to show', 'tainacan' ),
'label_unamed_process' => __( 'Unamed process', 'tainacan' ),
@ -301,7 +303,7 @@ return apply_filters( 'tainacan-admin-i18n', [
'label_show_filters' => __( 'Show filters menu', 'tainacan' ),
'label_select_all_items' => __( 'Select all items', 'tainacan' ),
'label_select_all' => __( 'Select all', 'tainacan' ),
'label_untrash_selected_items' => __( 'Remove from trash the selected items', 'tainacan' ),
'label_untrash_selected_items' => __( 'Recover from trash', 'tainacan' ),
'label_value_not_informed' => __( 'Value not informed.', 'tainacan' ),
'label_description_not_informed' => __( 'Description not informed.', 'tainacan' ),
'label_hide_metadata' => __( 'Hide metadata', 'tainacan' ),
@ -344,6 +346,7 @@ return apply_filters( 'tainacan-admin-i18n', [
'instruction_type_existing_term' => __( 'Type to add an existing term...', 'tainacan' ),
// Info. Other feedback to user.
'info_error_invalid_date' => __( 'Invalid date', 'tainacan' ),
'info_search_results' => __( 'Search Results', 'tainacan' ),
'info_search_criteria' => __( 'Search Criteria', 'tainacan' ),
'info_name_is_required' => __( 'Name is required.', 'tainacan' ),
@ -443,7 +446,7 @@ return apply_filters( 'tainacan-admin-i18n', [
'info_there_are_no_metadata_in_repository_level' => __( 'There are no metadata in repository level', 'tainacan' ),
'info_import_collection' => __( 'Import from external sources.', 'tainacan' ),
'info_import_items' => __( 'Import items from external sources.', 'tainacan' ),
'info_editing_items_in_bulk' => __( 'Editing items in bulk', 'tainacan' ),
'info_editing_items_in_bulk' => __( 'Bulk edit items', 'tainacan' ),
'info_by_inner' => __( 'by', 'tainacan' ),
'info_items_selected' => __( 'items selected', 'tainacan' ),
'info_items_affected' => __( 'items affected', 'tainacan' ),

View File

@ -164,7 +164,7 @@ class REST_Controller extends \WP_REST_Controller {
foreach ( $request_meta_query as $index1 => $a ) {
// handle core metadatum
if( is_array($a) && array_key_exists("key", $a) && !$request['advancedSearch'] ){
if( is_array($a) && array_key_exists("key", $a) && ( !isset($request['advancedSearch']) || !$request['advancedSearch'] ) ){
$metadatum = new \Tainacan\Entities\Metadatum($a['key']);
if( strpos( $metadatum->get_metadata_type(), 'Core_Title') !== false ){
$args[ 'post_title_in' ] = [

View File

@ -235,12 +235,19 @@ class REST_Background_Processes_Controller extends REST_Controller {
}
}
$query = "UPDATE $this->table $status_q WHERE 1=1 $id_q $user_q";
$query = "UPDATE $this->table SET $status_q WHERE 1=1 $id_q $user_q";
$result = $wpdb->query($query);
$query = "SELECT * FROM $this->table WHERE 1=1 $id_q $user_q LIMIT 1";
$result = $wpdb->get_row($query);
$result = $this->prepare_item_for_response($result, $request);
return new \WP_REST_Response( $result, 200 );
}
public function delete_item( $request ) {

View File

@ -183,12 +183,12 @@ class REST_Bulkedit_Controller extends REST_Controller {
$args['items_ids'] = $body['items_ids'];
} elseif ( isset($body['use_query']) && $body['use_query'] ) {
unset($request['paged']);
unset($request['offset']);
unset($request['perpage']);
$request['nopaging'] = 1;
unset($body['use_query']['paged']);
unset($body['use_query']['offset']);
unset($body['use_query']['perpage']);
$body['use_query']['nopaging'] = 1;
$query_args = $this->prepare_filters($request);
$query_args = $this->prepare_filters($body['use_query']);
$collection_id = $request['collection_id'];

View File

@ -47,7 +47,7 @@ class REST_Facets_Controller extends REST_Controller {
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_item'),
'permission_callback' => array($this, 'get_item_permissions_check')
'permission_callback' => array($this, 'get_items_permissions_check')
)
));
}
@ -100,41 +100,41 @@ class REST_Facets_Controller extends REST_Controller {
if(isset($request['number'])){
$args['posts_per_page'] = $request['number'];
}
$items = $this->items_repository->fetch($args, $options['collection_id'], 'WP_Query');
$ids = [];
if ($items->have_posts()) {
while ( $items->have_posts() ) {
$items->the_post();
$ids[] = (string) $items->post->ID;
$item = new Entities\Item($items->post);
$prepared_item = $restItemsClass->prepare_item_for_response($item, $request);
array_push($response, $prepared_item);
}
wp_reset_postdata();
}
// retrieve selected items
if( $selected && $request['getSelected'] && $request['getSelected'] === '1' ){
foreach( $selected as $index => $item_id ){
if( in_array($item_id,$ids) ){
continue;
}
$item = new Entities\Item($item_id);
$prepared_item = $restItemsClass->prepare_item_for_response($item, $request);
$response[$index] = $prepared_item;
$response[] = $prepared_item;
$ids[] = $item_id;
}
}
if( isset($request['number']) && ($index+1) >= $request['number']){
if ($items->have_posts()) {
while ( $items->have_posts() ) {
$items->the_post();
$item = new Entities\Item($items->post);
$prepared_item = $restItemsClass->prepare_item_for_response($item, $request);
if( in_array((string) $items->post->ID,$ids) ){
continue;
}
if( isset($request['number']) && count($response) >= $request['number']){
break;
}
array_push($response, $prepared_item);
}
wp_reset_postdata();
}
$this->total_items = $items->found_posts;
@ -173,7 +173,7 @@ class REST_Facets_Controller extends REST_Controller {
foreach( $terms as $index => $term ){
if( in_array($term->WP_Term->term_id,$selected) ){
if( in_array($term->WP_Term->term_id, $selected) ){
continue;
}
@ -232,21 +232,29 @@ class REST_Facets_Controller extends REST_Controller {
if( $selected && $request['getSelected'] && $request['getSelected'] === '1'){
$rawValues = $this->get_values( $response );
foreach( $selected as $index => $value ){
$realResponse = [];
if( in_array($value,$rawValues) ){
foreach( $selected as $index => $value ){
$row = ['mvalue' => $value, 'metadatum_id' => $metadatum_id ];
$realResponse[] = $row;
}
foreach( $rawValues as $index => $row0 ){
if( in_array($row0, $selected) ){
continue;
}
$row = ['mvalue' => $value, 'metadatum_id' => $metadatum_id ];
$response[$index] = $row;
$realResponse[] = ['mvalue' => $row0, 'metadatum_id' => $metadatum_id];
if( isset($request['number']) && ($index+1) >= $request['number']){
if( isset($request['number']) && count($realResponse) >= $request['number']){
break;
}
}
$response = $realResponse;
}
$this->set_pagination_properties_text_type( $collection_id, $metadatum_id, ($request['search']) ? $request['search'] : '' , $offset, $number );

View File

@ -356,7 +356,9 @@ class Bulk_Edit {
$select_q = $this->_build_select( 'post_id' );
$query_delete = "DELETE FROM $wpdb->posts WHERE ID IN ($select_q)";
$security = " AND post_status = 'trash'";
$query_delete = "DELETE FROM $wpdb->posts WHERE ID IN ($select_q) $security";
return $wpdb->query($query_delete);

View File

@ -1,5 +1,11 @@
<template>
<div class="block">
<span
v-if="isLoading"
style="width: 100%"
class="icon has-text-centered loading-icon">
<div class="control has-icons-right is-loading is-clearfix" />
</span>
<div
v-for="(option, index) in options.slice(0, filter.max_options)"
:key="index"
@ -115,6 +121,8 @@
promise = this.getValuesRelationship( collectionTarget, null, [], 0, this.filter.max_options, false, '1');
promise
.then(() => {
this.isLoading = false;
if(this.options.length > this.filter.max_options){
this.options.splice(this.filter.max_options);
}
@ -125,6 +133,8 @@
promise = this.getValuesPlainText( this.metadatum, null, this.isRepositoryLevel, [], 0, this.filter.max_options, false, '1' );
promise
.then(() => {
this.isLoading = false;
if(this.options.length > this.filter.max_options){
this.options.splice(this.filter.max_options);
}
@ -213,4 +223,10 @@
display: flex;
padding-left: 18px;
}
.is-loading:after {
border: 2px solid white !important;
border-top-color: #dbdbdb !important;
border-right-color: #dbdbdb !important;
}
</style>

View File

@ -36,7 +36,7 @@ export const filter_type_mixin = {
} else if(search){
url += `search=${search}&` + qs.stringify(query_items);
} else {
url += qs.stringify(query_items);
url += qs.stringify(query_items, { addQueryPrefix: true });
}
return axios.get(url)

View File

@ -1,5 +1,11 @@
<template>
<div class="block">
<span
v-if="isLoading"
style="width: 100%"
class="icon has-text-centered loading-icon">
<div class="control has-icons-right is-loading is-clearfix" />
</span>
<div
v-for="(option, index) in options.slice(0, filter.max_options)"
:key="index"
@ -98,8 +104,15 @@
this.isLoading = true;
let query_items = { 'current_query': this.query };
axios.get('/collection/'+ this.collection +'/facets/' + this.metadatum
+ `?getSelected=1&hideempty=0&order=asc&parent=0&number=${this.filter.max_options}&` + qs.stringify(query_items))
let route = `/collection/${this.collection}/facets/${this.metadatum}?getSelected=1&hideempty=0&order=asc&parent=0&number=${this.filter.max_options}&` + qs.stringify(query_items);
if(this.collection == 'filter_in_repository'){
route = `/facets/${this.metadatum}?getSelected=1&hideempty=0&order=asc&parent=0&number=${this.filter.max_options}&` + qs.stringify(query_items);
}
this.options = [];
axios.get(route)
.then( res => {
for (let item of res.data) {
@ -172,7 +185,14 @@
if (valueIndex >= 0) {
onlyLabels.push(this.options[valueIndex].label)
} else {
axios.get('/collection/'+ this.collection +'/facets/' + this.metadatum +`?term_id=${selected}&fetch_only[0]=name&fetch_only[1]=id`)
let route = '/collection/'+ this.collection +'/facets/' + this.metadatum +`?term_id=${selected}&fetch_only[0]=name&fetch_only[1]=id`;
if(this.collection == 'filter_in_repository'){
route = '/facets/' + this.metadatum +`?term_id=${selected}&fetch_only[0]=name&fetch_only[1]=id`
}
axios.get(route)
.then( res => {
if(!res || !res.data){
@ -227,4 +247,10 @@
display: flex;
padding-left: 18px;
}
.is-loading:after {
border: 2px solid white !important;
border-top-color: #dbdbdb !important;
border-right-color: #dbdbdb !important;
}
</style>

View File

@ -1,145 +0,0 @@
<template>
<div class="block">
<b-select
:id="id"
:loading="isLoading"
:value="selected"
@input="onSelect($event)"
size="is-small"
expanded
:placeholder="$i18n.get('label_selectbox_init')">
<option value="">{{ $i18n.get('label_selectbox_init') }}...</option>
<option
v-for=" (option, index) in options"
:key="index"
:label="option.label"
:value="option.value">{{ option.label }}</option>
</b-select>
</div>
</template>
<script>
import qs from 'qs';
import { tainacan as axios } from "../../../js/axios/axios";
export default {
created() {
this.collection = this.collection_id
? this.collection_id
: this.filter.collection_id;
this.metadatum = this.metadatum_id
? this.metadatum_id
: this.filter.metadatum.metadatum_id;
this.type = this.filter_type
? this.filter_type
: this.filter.metadatum.metadata_type;
this.loadOptions();
this.$eventBusSearch.$on("removeFromFilterTag", filterTag => {
if (filterTag.filterId == this.filter.id) {
this.onSelect();
}
});
},
data() {
return {
isLoading: false,
options: [],
collection: "",
metadatum: "",
selected: "",
taxonomy: ""
};
},
props: {
filter: {
type: Object // concentrate all attributes metadatum id and type
},
metadatum_id: [Number], // not required, but overrides the filter metadatum id if is set
collection_id: [Number], // not required, but overrides the filter metadatum id if is set
filter_type: [String], // not required, but overrides the filter metadatum type if is set
id: "",
query: {
type: Object // concentrate all attributes metadatum id and type
}
},
methods: {
loadOptions() {
this.isLoading = true;
let query_items = { 'current_query': this.query };
axios.get('/collection/'+ this.collection +'/facets/' + this.metadatum + `?hideempty=0&order=asc&` + qs.stringify(query_items))
.then( res => {
for (let item of res.data) {
this.taxonomy = item.taxonomy;
this.taxonomy_id = item.taxonomy_id;
this.options.push(item);
}
this.isLoading = false;
this.selectedValues();
})
.catch(error => {
this.$console.log(error);
this.isLoading = false;
});
},
getOptions(parent, level = 0) {
// retrieve only ids
let result = [];
if (this.options) {
for (let term of this.options) {
if (term.parent == parent) {
term["level"] = level;
result.push(term);
const levelTerm = level + 1;
const children = this.getOptions(term.value, levelTerm);
result = result.concat(children);
}
}
}
return result;
},
selectedValues() {
if (
!this.query ||
!this.query.taxquery ||
!Array.isArray(this.query.taxquery)
)
return false;
let index = this.query.taxquery.findIndex(
newMetadatum => newMetadatum.taxonomy === this.taxonomy
);
if (index >= 0) {
let metadata = this.query.taxquery[index];
this.selected = metadata.terms;
} else {
return false;
}
},
onSelect(value) {
this.selected = value;
this.$emit("input", {
filter: "selectbox",
compare: "IN",
taxonomy: this.taxonomy,
metadatum_id: this.metadatum,
collection_id: this.collection,
terms: this.selected
});
let valueIndex = this.options.findIndex(
option => option.value == this.selected
);
if (valueIndex >= 0) {
this.$eventBusSearch.$emit("sendValuesToTags", {
filterId: this.filter.id,
value: this.options[valueIndex].label
});
}
}
}
};
</script>

View File

@ -22,6 +22,6 @@ class TaxonomyCheckbox extends Filter_Type {
return '<tainacan-filter-taxonomy-checkbox name="'.$filter->get_name().'"
filter_type="'.$filter->get_metadatum()->get_metadata_type().'"
collection_id="'.$filter->get_collection_id().'"
metadatum_id="'.$filter->get_metadatum()->get_id().'"></tainacan-filter-checkbox>';
metadatum_id="'.$filter->get_metadatum()->get_id().'"></tainacan-filter-taxonomy-checkbox>';
}
}

View File

@ -1,27 +0,0 @@
<?php
namespace Tainacan\Filter_Types;
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
/**
* Class TainacanMetadatumType
*/
class TaxonomySelectbox extends Filter_Type {
function __construct(){
$this->set_supported_types(['term']);
$this->set_component('tainacan-filter-taxonomy-selectbox');
}
/**
* @param $filter
* @return string
*/
public function render( $filter ){
return '<tainacan-filter-taxonomy-selectbox name="'.$filter->get_name().'"
filter_type="'.$filter->get_metadatum()->get_metadata_type().'"
collection_id="'.$filter->get_collection_id().'"
metadatum_id="'.$filter->get_metadatum()->get_id().'"></tainacan-filter-selectbox>';
}
}

View File

@ -22,6 +22,6 @@ class TaxonomyTaginput extends Filter_Type {
return '<tainacan-filter-taxonomy-taginput name="'.$filter->get_name().'"
filter_type="'.$filter->get_metadatum()->get_metadata_type().'"
collection_id="'.$filter->get_collection_id().'"
metadatum_id="'.$filter->get_metadatum()->get_id().'"></tainacan-filter-taginput>';
metadatum_id="'.$filter->get_metadatum()->get_id().'"></tainacan-filter-taxonomy-taginput>';
}
}

View File

@ -6,12 +6,16 @@
<input
:disabled="disabled"
class="input"
:class="{'is-danger': isInvalidDate && dateValue}"
type="text"
v-mask="dateMask"
:value="dateValue"
v-model="dateValue"
@blur="onBlur"
@input="onInput"
:placeholder="dateFormat.toLowerCase()">
<p
v-if="isInvalidDate && dateValue"
class="has-text-danger is-italic is-size-7">{{ $i18n.get('info_error_invalid_date') }}</p>
<!--<b-collapse-->
<!--position="is-bottom-right">-->
<!--<b-icon-->
@ -57,7 +61,8 @@
return {
dateValue: '',
dateMask: this.getDateLocaleMask(),
dateFormat: ''
dateFormat: '',
isInvalidDate: false,
}
},
props: {
@ -72,18 +77,25 @@
onBlur() {
this.$emit('blur');
},
onInput($event) {
onInput: _.debounce(function ($event) {
let dateISO = '';
if($event && $event instanceof Date) {
dateISO = moment(this.dateValue, this.dateFormat).toISOString().split('T')[0];
dateISO = moment(this.dateValue, this.dateFormat).toISOString() ? moment(this.dateValue, this.dateFormat).toISOString().split('T')[0] : false;
} else if($event.target.value && $event.target.value.length === this.dateMask.length) {
dateISO = moment($event.target.value, this.dateFormat).toISOString().split('T')[0];
dateISO = moment(this.dateValue, this.dateFormat).toISOString() ? moment($event.target.value, this.dateFormat).toISOString().split('T')[0] : false;
}
if(!dateISO){
this.isInvalidDate = true;
return;
} else {
this.isInvalidDate = false;
}
this.$emit('input', dateISO);
this.$emit('blur');
},
}, 300),
parseDateToNavigatorLanguage(date){
date = new Date(date.replace(/-/g, '/'));

View File

@ -2,6 +2,8 @@
namespace Tainacan\Metadata_Types;
use Tainacan\Entities\Item_Metadata_Entity;
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
use Tainacan\Helpers;
@ -28,4 +30,19 @@ class Date extends Metadata_Type {
value=\''.json_encode( $itemMetadata->get_value() ).'\'
name="'.$itemMetadata->get_metadatum()->get_name().'"></tainacan-date>';
}
public function validate( Item_Metadata_Entity $item_metadata) {
$value = $item_metadata->get_value();
$format = 'Y-m-d';
$d = \DateTime::createFromFormat($format, $value);
return $d && $d->format($format) === $value;
}
}

View File

@ -107,7 +107,6 @@
}
this.single_types['tainacan-taxonomy-radio'] = 'Radio';
this.single_types['tainacan-taxonomy-selectbox'] = 'Selectbox';
this.multiple_types['tainacan-taxonomy-tag-input'] = 'Tag Input';
this.multiple_types['tainacan-taxonomy-checkbox'] = 'Checkbox';

View File

@ -8,19 +8,20 @@
:allow-select-to-create="allowSelectToCreate"
:allow-new="allowNew"
:terms="terms"
:taxonomy-id="taxonomy"
:taxonomy-id="taxonomy_id"
:options="getOptions(0)"/>
<a
<a
class="add-new-term"
v-if="(getComponent == 'tainacan-taxonomy-checkbox' || getComponent == 'tainacan-taxonomy-radio') && terms.length < totalTerms"
@click="getTermsFromTaxonomy()">
{{ $i18n.get('label_view_more') + ' (' + Number(totalTerms - terms.length) + ' ' + $i18n.get('terms') + ')' }}
v-if="(this.getComponent == 'tainacan-taxonomy-checkbox' || this.getComponent == 'tainacan-taxonomy-radio') &&
terms.length < totalTerms"
@click="openCheckboxModal()">
{{ $i18n.get('label_view_all') }}
</a>
<add-new-term
class="add-new-term"
v-if="allowNew"
:component-type="getComponent"
:taxonomy_id="taxonomy"
:taxonomy_id="taxonomy_id"
:metadatum="metadatum"
:item_id="metadatum.item.id"
:value="valueComponent"
@ -33,8 +34,8 @@
import TainacanTaxonomyRadio from './TaxonomyRadio.vue'
import TainacanTaxonomyCheckbox from './TaxonomyCheckbox.vue'
import TainacanTaxonomyTagInput from './TaxonomyTaginput.vue'
import TainacanTaxonomySelectbox from './TaxonomySelectbox.vue'
import AddNewTerm from './AddNewTerm.vue'
import HierarchicalCheckboxModal from '../../../admin/components/other/checkbox-filter-modal.vue'
export default {
created(){
@ -43,7 +44,8 @@
? this.metadatum.metadatum.metadata_type_options.input_type : this.componentAttribute;
this.collectionId = this.metadatum.metadatum.collection_id;
this.taxonomy = metadata_type_options.taxonomy_id;
this.taxonomy_id = metadata_type_options.taxonomy_id;
this.taxonomy = metadata_type_options.taxonomy;
if( metadata_type_options && metadata_type_options.allow_new_terms && this.metadatum.item ){
this.allowNew = metadata_type_options.allow_new_terms == 'yes';
@ -60,7 +62,6 @@
TainacanTaxonomyRadio,
TainacanTaxonomyCheckbox,
TainacanTaxonomyTagInput,
TainacanTaxonomySelectbox,
AddNewTerm
},
data(){
@ -68,12 +69,13 @@
valueComponent: null,
component: '',
collectionId: '',
taxonomy_id: '',
taxonomy: '',
terms:[], // object with names
totalTerms: 0,
allowNew: false,
offset: 0,
termsNumber: 40
termsNumber: 12
}
},
watch: {
@ -109,8 +111,33 @@
}
},
methods: {
openCheckboxModal(){
this.$modal.open({
parent: this,
component: HierarchicalCheckboxModal,
props: {
isFilter: false,
parent: 0,
taxonomy_id: this.taxonomy_id,
selected: !this.valueComponent ? [] : this.valueComponent,
metadatum_id: this.metadatum.metadatum.id,
taxonomy: this.taxonomy,
collection_id: this.collectionId,
isTaxonomy: true,
query: '',
metadatum: this.metadatum.metadatum,
isCheckbox: this.getComponent == 'tainacan-taxonomy-checkbox'
},
events: {
input: (selected) => {
this.valueComponent = selected;
}
},
width: 'calc(100% - 8.333333333%)',
});
},
getTermsFromTaxonomy(){
let endpoint = '/taxonomy/' + this.taxonomy + '/terms?hideempty=0&order=asc';
let endpoint = '/taxonomy/' + this.taxonomy_id + '/terms?hideempty=0&order=asc';
if (this.getComponent == 'tainacan-taxonomy-checkbox' || this.getComponent == 'tainacan-taxonomy-radio')
endpoint = endpoint + '&number=' + this.termsNumber + '&offset=' + this.offset;
@ -169,11 +196,12 @@
},
onInput($event) {
this.inputValue = $event;
this.valueComponent = $event;
this.$emit('input', this.inputValue);
this.$emit('blur');
},
reload( $event ) {
if ($event.taxonomyId == this.taxonomy && $event.metadatumId == this.metadatum.metadatum.id) {
if ($event.taxonomyId == this.taxonomy_id && $event.metadatumId == this.metadatum.metadatum.id) {
this.valueComponent = $event.values;
this.terms = [];
this.offset = 0;

View File

@ -46,7 +46,7 @@
methods: {
onChecked() {
this.$emit('blur');
this.onInput(this.checked)
this.onInput(this.checked);
},
onInput($event) {
this.inputValue = $event;

View File

@ -1,6 +1,15 @@
<template>
<div>
<div
<b-radio
:disabled="disabled"
:id="id"
v-model="checked"
@input="onChecked()"
:native-value="''"
border>
{{ $i18n.get('clear_radio') }}
</b-radio>
<div
v-for="(option, index) in options"
:key="index">
<b-radio

View File

@ -1,62 +0,0 @@
<template>
<div>
<div class="block">
<b-select
:disabled="disabled"
:id="id"
v-model="selected"
@input="emitChange()"
:placeholder="$i18n.get('label_select_taxonomy')"
expanded>
<option
v-for="(option, index) in options"
:key="index"
:value="option.id"
v-html="setSpaces( option.level ) + option.name"/>
</b-select>
</div>
</div>
</template>
<script>
export default {
created(){
if( this.value )
this.selected = this.value;
},
data(){
return {
selected: ''
}
},
watch: {
value( val ){
this.selected = val;
}
},
props: {
id: String,
options: {
type: Array
},
value: [ Number, String, Array ],
disabled: false,
},
methods: {
emitChange() {
this.$emit('input', this.selected);
this.$emit('blur');
},
setSpaces( level ){
let result = '';
let space = '&nbsp;&nbsp;'
for(let i = 0;i < level; i++)
result += space;
return result;
}
}
}
</script>

View File

@ -77,7 +77,7 @@ class Terms extends Repository {
'description' => __( 'The term creator', 'tainacan' ),
'on_error' => __( 'The user is empty or invalid', 'tainacan' ),
'default' => get_current_user_id(),
'validation' => v::numeric(),
//'validation' => v::numeric(),
],
'header_image_id' => [
'map' => 'termmeta',
@ -222,7 +222,6 @@ class Terms extends Repository {
foreach ( $terms as $term ) {
$tainacan_term = new Entities\Term( $term );
$tainacan_term->set_user( get_term_meta( $tainacan_term->get_id(), 'user', true ) );
$return[] = $tainacan_term;
}
@ -230,8 +229,6 @@ class Terms extends Repository {
} elseif ( is_numeric( $args ) && ! empty( $cpt ) && ! is_array( $cpt ) ) { // if an id is passed taxonomy cannot be an array
$wp_term = get_term_by( 'id', $args, $cpt );
$tainacan_term = new Entities\Term( $wp_term );
$tainacan_term->set_user( get_term_meta( $tainacan_term->get_id(), 'user', true ) );
return $tainacan_term;
} else {
return [];

View File

@ -27,6 +27,7 @@ const DIRS = [
require_once('libs/wp-async-request.php');
require_once('libs/wp-background-process.php');
require_once('class-tainacan-background-process.php');
require_once('tainacan-utils.php');
require_once(TAINACAN_IMPORTER_DIR . 'class-tainacan-bg-importer.php');
require_once(TAINACAN_VENDOR_DIR . 'autoload.php');
@ -72,7 +73,7 @@ function tainacan_autoload($class_name){
}
if( in_array('Metadata_Types', $class_path) || in_array('Filter_Types', $class_path) ){
$exceptions = ['taxonomytaginput','taxonomycheckbox','taxonomyselectbox'];
$exceptions = ['taxonomytaginput','taxonomycheckbox'];
if( in_array( strtolower( $class_name ), $exceptions) ){
$dir.= 'taxonomy/';
}else{
@ -114,7 +115,6 @@ $Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Taginput');
$Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Checkbox');
$Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\TaxonomyTaginput');
$Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\TaxonomyCheckbox');
$Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\TaxonomySelectbox');
$Tainacan_Taxonomies = \Tainacan\Repositories\Taxonomies::get_instance();

View File

@ -0,0 +1,15 @@
<?php
/**
* This file gathers functions usefull for theme and plugin developers
*/
/**
* Retrieves raw data sent to an API endpoint reading the php://input stream
* @return Object PHP Raw Postdata
*/
function tainacan_get_api_postdata() {
$postdata = file_get_contents("php://input");
$post = json_decode($postdata);
return $post;
}

View File

@ -13,7 +13,7 @@ class CSV extends Importer {
'delimiter' => ',',
'multivalued_delimiter' => '||',
'encode' => 'utf8',
'enclosure' => '"'
'enclosure' => ''
]);
}
@ -31,7 +31,13 @@ class CSV extends Importer {
public function get_source_metadata(){
if (($handle = fopen($this->tmp_file, "r")) !== false) {
$rawColumns = fgetcsv($handle, 0, $this->get_option('delimiter'));
if( $this->get_option('enclosure') && strlen($this->get_option('enclosure')) > 0 ){
$rawColumns = $this->handle_enclosure( $handle );
} else {
$rawColumns = fgetcsv($handle, 0, $this->get_option('delimiter'));
}
$columns = [];
if( $rawColumns ){
@ -64,7 +70,13 @@ class CSV extends Importer {
public function raw_source_metadata(){
if (($handle = fopen($this->tmp_file, "r")) !== false) {
return fgetcsv($handle, 0, $this->get_option('delimiter'));
if( $this->get_option('enclosure') && strlen($this->get_option('enclosure')) > 0 ){
return $this->handle_enclosure( $handle );
} else {
return fgetcsv($handle, 0, $this->get_option('delimiter'));
}
}
return false;
@ -103,7 +115,14 @@ class CSV extends Importer {
}
$this->add_transient('csv_last_pointer', ftell($file)); // add reference to post_process item in after_inserted_item()
$values = fgetcsv($file, 0, $this->get_option('delimiter'), $this->get_option('enclosure'));
if( $this->get_option('enclosure') && strlen($this->get_option('enclosure')) > 0 ){
$values = $this->handle_enclosure( $file );
} else {
$values = fgetcsv($file, 0, $this->get_option('delimiter'));
}
$this->add_transient('csv_pointer', ftell($file)); // add reference for insert
if( count( $headers ) !== count( $values ) ){
@ -112,7 +131,7 @@ class CSV extends Importer {
$this->add_error_log(' Mismatch count headers and row columns ');
$this->add_error_log(' Headers count: ' . count( $headers ) );
$this->add_error_log(' Values count: ' . count( $values ) );
$this->add_error_log(' enclosure : ' . $enclosure );
$this->add_error_log(' enclosure : ' . $this->get_option('enclosure') );
$this->add_error_log(' Values string: ' . $string );
return false;
}
@ -158,7 +177,12 @@ class CSV extends Importer {
$csv_pointer= $this->get_transient('csv_last_pointer');
fseek($file, $csv_pointer);
$values = fgetcsv($file, 0, $this->get_option('delimiter'), $this->get_option('enclosure'));
if( $this->get_option('enclosure') && strlen($this->get_option('enclosure')) > 0 ){
$values = $this->handle_enclosure( $file );
} else {
$values = fgetcsv($file, 0, $this->get_option('delimiter'));
}
if( is_array($values) && !empty($column_document) ){
$this->handle_document( $values[$column_document], $inserted_item);
@ -460,4 +484,29 @@ class CSV extends Importer {
$this->items_repo->enable_logs();
}
/**
* @param $file resource the csv file uploaded
*/
private function handle_enclosure( &$file ){
$line = trim(fgets($file));
$start = substr($line, 0, strlen($this->get_option('enclosure')));
if( $this->get_option('enclosure') === $start ){
$cut_start = strlen($this->get_option('enclosure'));
$line = substr($line, $cut_start);
}
$end = substr($line, ( strlen($line) - strlen($this->get_option('enclosure')) ) , strlen($this->get_option('enclosure')));
if( $this->get_option('enclosure') === $end ){
$line = substr($line, 0, ( strlen($line) - strlen($this->get_option('enclosure')) ) );
}
$delimiter = $this->get_option('enclosure').$this->get_option('delimiter').$this->get_option('enclosure');
$values = explode($delimiter, $line);
return $values;
}
}

View File

@ -643,6 +643,11 @@ class Old_Tainacan extends Importer{
if($term_father){
$new_term->set_parent($term_father->get_id());
}
// block terms with same name and parent in taxonomy
if( get_term_by( 'name', $term->name, $taxonomy_father->get_db_identifier()) ){
continue;
}
$inserted_term = $this->term_repo->insert($new_term);

View File

@ -56,7 +56,7 @@ class Test_Importer extends Importer {
];
protected $date_values = [
'03/04/1993', '03/12/1998', '10/09/2001', '03/01/2018', '13/11/2016', '22/04/1993'
'1993-12-03', '1998-04-03', '2001-09-10', '2018-01-03', '2016-11-13', '1993-04-22'
];
protected $numeric_values = [
@ -231,7 +231,7 @@ class Test_Importer extends Importer {
</div>
<div class="field">
<label class="label"><?php _e('Horizontal image size', 'tainacan'); ?></label>
<label class="label"><?php _e('Horizontal image size (0 for random)', 'tainacan'); ?></label>
<span class="help-wrapper">
<a class="help-button has-text-secondary">
<span class="icon is-small">
@ -243,7 +243,7 @@ class Test_Importer extends Importer {
<h5><?php _e('Horizontal image size', 'tainacan'); ?></h5>
</div>
<div class="help-tooltip-body">
<p><?php _e('Horizontal image size ( 0 for random size )', 'tainacan'); ?></p>
<p><?php _e('Horizontal image size in pixels ( 0 for random size )', 'tainacan'); ?></p>
</div>
</div>
</span>
@ -253,7 +253,7 @@ class Test_Importer extends Importer {
</div>
<div class="field">
<label class="label"><?php _e('Vertical image size', 'tainacan'); ?></label>
<label class="label"><?php _e('Vertical image size (0 for random)', 'tainacan'); ?></label>
<span class="help-wrapper">
<a class="help-button has-text-secondary">
<span class="icon is-small">
@ -265,7 +265,7 @@ class Test_Importer extends Importer {
<h5><?php _e('Vertical image size', 'tainacan'); ?></h5>
</div>
<div class="help-tooltip-body">
<p><?php _e('Vertical image size ( 0 for random size )', 'tainacan'); ?></p>
<p><?php _e('Vertical image size in pixels ( 0 for random size )', 'tainacan'); ?></p>
</div>
</div>
</span>

View File

@ -312,12 +312,10 @@ export default {
'taxonomy': this.taxonomy
})
.then((res) => {
this.$emit( 'isLoadingItems', false);
this.$emit( 'hasFiltered', res.hasFiltered);
if(res.advancedSearchResults){
this.$router.replace({query: this.$store.getters['search/getPostQuery'],});
this.$emit('advancedSearchResults', res.advancedSearchResults);
}
})

View File

@ -6,7 +6,7 @@ export const fetchProcesses = ({ commit }, {page, processesPerPage}) => {
let endpoint = '/bg-processes?all_users=1';
if (page != undefined)
endpoint += 'paged=' + page;
endpoint += '&paged=' + page;
if (processesPerPage != undefined)
endpoint += '&perpage=' + processesPerPage;

View File

@ -239,7 +239,19 @@ class Migrations {
['meta_value' => 'Tainacan\Filter_Types\TaxonomySelectbox'],
['meta_value' => 'Tainacan\Filter_Types\CategorySelectbox'],
'%s', '%s');
}
static function update_tainacan_selectbox_to_tainacan_radio_and_tainacan_taginput(){
global $wpdb;
// update filter type
$wpdb->update($wpdb->postmeta,
['meta_value' => 'Tainacan\Filter_Types\TaxonomyTaginput'],
['meta_value' => 'Tainacan\Filter_Types\TaxonomySelectbox'],
'%s', '%s');
// update input type
$wpdb->query("UPDATE $wpdb->postmeta SET meta_value = REPLACE(meta_value, 'tainacan-taxonomy-selectbox', 'tainacan-taxonomy-radio')");
}
static function update_core_metadata() {

View File

@ -1,10 +1,10 @@
=== Tainacan ===
Contributors: fabianobn, jacsonp, leogermani, weryques, wetah
Contributors: andrebenedito, fabianobn, jacsonp, leogermani, weryques, wetah
Tags: museums, libraries, archives, GLAM, collections, repository
Requires at least: 4.8
Tested up to: 4.9.7
Tested up to: 4.9.8
Requires PHP: 5.6
Stable tag: 0.3
Stable tag: 0.4
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html
@ -14,7 +14,7 @@ Tainacan is a powerful and flexible repository platform for WordPress. Manage an
Tainacan is a powerful and flexible repository platform for WordPress. Manage and publish you digital collections as easily as publishing a post to your blog, while having all the tools of a professional repository platform.
Please note: This is an early release of this plugin, and we are working hard to release 1.0 soon, please refer to the [project's website](http://tainacan.org/new) for more information and road map.
Please note: This is an early release of this plugin, and we are working hard to release 1.0 soon, please refer to the [project's website](http://tainacan.org/) for more information and road map.
= Features =
@ -86,4 +86,5 @@ If you have Imagick installed in your server, Tainacan will be able to automatic
7. Navigate through rich filtering interface
8. Explore more with Advanced Search
9. Set up Taxonomies to be used across your repository
10. Expose your collection using Tainacan default theme
10. Bulk edit as many items as you need quickly
11. Expose your collection using Tainacan default theme

View File

@ -1,10 +1,10 @@
<?php
/*
Plugin Name: Tainacan
Plugin URI: https://tainacan.org/new
Plugin URI: https://tainacan.org/
Description: powerfull and flexible repository platform for WordPress. Manage and publish you digital collections as easily as publishing a post to your blog, while having all the tools of a professional respository platform.
Author: Media Lab / UFG
Version: 0.3
Version: 0.4
Text Domain: tainacan
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html

View File

@ -86,12 +86,8 @@ function tainacan_the_document() {
* @return bool True if item has document, false if it does not
*/
function tainacan_has_document() {
$item = tainacan_get_item();
if (!$item)
return;
$document = $item->get_document();
$document = tainacan_get_the_document();
return ! empty($document);

View File

@ -948,9 +948,9 @@ class BulkEdit extends TAINACAN_UnitApiTestCase {
'POST', $this->api_baseroute
);
$request->set_query_params($query);
//$request->set_query_params($query);
$request->set_body( json_encode(['use_query' => 1]) );
$request->set_body( json_encode(['use_query' => $query]) );
$response = $this->server->dispatch($request);
@ -1128,6 +1128,10 @@ class BulkEdit extends TAINACAN_UnitApiTestCase {
'items_ids' => $ids,
]);
$this->assertEquals( 0, $bulk->delete_items(), 'Items must be on trash to be deleted' );
$bulk->trash_items();
$this->assertEquals( 17, $bulk->delete_items() );
$Tainacan_Items = \Tainacan\Repositories\Items::get_instance();
@ -1272,5 +1276,32 @@ class BulkEdit extends TAINACAN_UnitApiTestCase {
}
function test_create_delete_group() {
$Tainacan_Items = \Tainacan\Repositories\Items::get_instance();
$ids = array_slice($this->items_ids, 2, 7);
$bulk = new \Tainacan\Bulk_Edit([
'items_ids' => $ids,
]);
$bulk->trash_items();
$query = [
'status' => 'trash',
'posts_per_page' => -1
];
$bulk = new \Tainacan\Bulk_Edit([
'query' => $query,
'collection_id' => $this->collection->get_id()
]);
$this->assertEquals(7, $bulk->count_posts());
}
}

View File

@ -0,0 +1,81 @@
<?php
namespace Tainacan\Tests;
/**
* Class TestCollections
*
* @package Test_Tainacan
*/
use Tainacan\Entities;
/**
* Sample test case.
*/
class DateMetadatumTypes extends TAINACAN_UnitTestCase {
function test_date_metadata_types() {
$Tainacan_Metadata = \Tainacan\Repositories\Metadata::get_instance();
$Tainacan_Item_Metadata = \Tainacan\Repositories\Item_Metadata::get_instance();
$Tainacan_Items = \Tainacan\Repositories\Items::get_instance();
$collection = $this->tainacan_entity_factory->create_entity(
'collection',
array(
'name' => 'test',
),
true
);
$metadatum = $this->tainacan_entity_factory->create_entity(
'metadatum',
array(
'name' => 'meta',
'description' => 'description',
'collection' => $collection,
'metadata_type' => 'Tainacan\Metadata_Types\Date',
'status' => 'publish',
),
true
);
$i = $this->tainacan_entity_factory->create_entity(
'item',
array(
'title' => 'item test',
'description' => 'adasdasdsa',
'collection' => $collection,
'status' => 'publish',
),
true
);
$item_metadata = new \Tainacan\Entities\Item_Metadata_Entity($i, $metadatum);
$item_metadata->set_value('2010-01-01');
$this->assertTrue($item_metadata->validate());
$item_metadata->set_value('2010-12-01');
$this->assertTrue($item_metadata->validate());
$item_metadata->set_value('2010-12-31');
$this->assertTrue($item_metadata->validate());
$item_metadata->set_value('2010-22-01');
$this->assertFalse($item_metadata->validate());
$item_metadata->set_value('3/3/1202');
$this->assertFalse($item_metadata->validate());
$item_metadata->set_value('2010-02-30');
$this->assertFalse($item_metadata->validate());
}
}

View File

@ -99,7 +99,7 @@ class Filters extends TAINACAN_UnitTestCase {
$Tainacan_Filters = \Tainacan\Repositories\Filters::get_instance();
$all_filter_types = $Tainacan_Filters->fetch_filter_types();
$this->assertEquals( 8, count( $all_filter_types ) );
$this->assertEquals( 7, count( $all_filter_types ) );
$float_filters = $Tainacan_Filters->fetch_supported_filter_types('float');
$this->assertTrue( count( $float_filters ) > 0 );

Binary file not shown.

Before

Width:  |  Height:  |  Size: 498 KiB

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 KiB

After

Width:  |  Height:  |  Size: 410 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 65 KiB