Creates first version of dates intersection filter. #887.
This commit is contained in:
parent
2f127030ed
commit
685b61b0b1
|
@ -252,13 +252,15 @@ import { formHooks } from "../../js/mixins";
|
|||
import FormFilterNumeric from '../filter-types/numeric/FormNumeric.vue';
|
||||
import FormFilterNumericInterval from '../filter-types/numeric-interval/FormNumericInterval.vue';
|
||||
import FormFilterNumericListInterval from '../filter-types/numeric-list-interval/FormNumericListInterval.vue';
|
||||
import FormFilterDatesIntersection from '../filter-types/dates-intersection/FormDatesIntersection.vue';
|
||||
|
||||
export default {
|
||||
name: 'FilterEditionForm',
|
||||
components: {
|
||||
'tainacan-filter-form-numeric': FormFilterNumeric,
|
||||
'tainacan-filter-form-numeric-interval': FormFilterNumericInterval,
|
||||
'tainacan-filter-form-numeric-list-interval': FormFilterNumericListInterval
|
||||
'tainacan-filter-form-numeric-list-interval': FormFilterNumericListInterval,
|
||||
'tainacan-filter-form-dates-intersection': FormFilterDatesIntersection
|
||||
},
|
||||
mixins: [ formHooks ],
|
||||
props: {
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
<template>
|
||||
<div>
|
||||
<b-field
|
||||
:addons="false"
|
||||
:type="metadataType"
|
||||
:message="metadataMessage">
|
||||
<label class="label is-inline">
|
||||
{{ $i18n.getHelperTitle('tainacan-filter-dates-intersection', 'secondary_filter_metadatum_id') }}<span :class="metadataType"> * </span>
|
||||
<help-button
|
||||
:title="$i18n.getHelperTitle('tainacan-filter-dates-intersection', 'secondary_filter_metadatum_id')"
|
||||
:message="$i18n.getHelperMessage('tainacan-filter-dates-intersection', 'secondary_filter_metadatum_id')" />
|
||||
</label>
|
||||
<b-select
|
||||
v-model="secondDateMetadatumId"
|
||||
name="dates_intersect[secondary_filter_metadatum_id]"
|
||||
:placeholder="$i18n.get('instruction_select_second_date_to_compare' )"
|
||||
:loading="loading"
|
||||
expanded
|
||||
@change="onUpdateSecondDateMetadatumId()"
|
||||
@focus="clear()">
|
||||
<option :value="''">
|
||||
{{ $i18n.get('instruction_select_second_date_to_compare' ) }}
|
||||
</option>
|
||||
<option
|
||||
v-for="option in metadata.filter(aMetadatum => aMetadatum.id != filter.metadatumId )"
|
||||
:key="option.id"
|
||||
:value="option.id">
|
||||
{{ option.name }}
|
||||
</option>
|
||||
</b-select>
|
||||
</b-field>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { tainacanApi } from '../../../js/axios';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
filter: Object,
|
||||
modelValue: Object,
|
||||
errors: Object
|
||||
},
|
||||
emits: [
|
||||
'update:model-value',
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
metadata: [],
|
||||
loading: true,
|
||||
metadataType: '',
|
||||
metadataMessage: '',
|
||||
secondDateMetadatumId: [Number, String]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
errors(){
|
||||
if ( this.errors && this.errors.secondary_filter_metadatum_id !== '' )
|
||||
this.setErrorsAttributes( 'is-danger', this.errors.secondary_filter_metadatum_id );
|
||||
else
|
||||
this.setErrorsAttributes( '', '' );
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.secondDateMetadatumId = this.modelValue && this.modelValue.secondary_filter_metadatum_id ? this.modelValue.secondary_filter_metadatum_id : '';
|
||||
this.loading = true;
|
||||
this.fetchMetadata();
|
||||
console.log(this.filter)
|
||||
},
|
||||
methods: {
|
||||
async fetchMetadata() {
|
||||
let endpoint = this.filter.collectionId && this.filter.collectionId !== 'default' ? ( '/collections/' + this.filter.collectionId + '/metadata' ) : '/metadata';
|
||||
return await tainacanApi.get(endpoint)
|
||||
.then(res => {
|
||||
this.loading = false;
|
||||
this.metadata = res.data ? res.data : [];
|
||||
})
|
||||
.catch(error => {
|
||||
this.loading = false;
|
||||
this.$console.log(error);
|
||||
});
|
||||
},
|
||||
onUpdateSecondDateMetadatumId() {
|
||||
const selectedMetadatum = this.metadata.find( aMetadatum => aMetadatum.id == this.secondDateMetadatumId );
|
||||
const selectedMetadatumName = selectedMetadatum ? selectedMetadatum.name : '';
|
||||
this.$emit('update:model-value', { secondary_filter_metadatum_id: this.secondDateMetadatumId, secondary_filter_metadatum_name: selectedMetadatumName});
|
||||
},
|
||||
setErrorsAttributes( type, message ) {
|
||||
this.metadataType = type;
|
||||
this.metadataMessage = message;
|
||||
},
|
||||
clear(){
|
||||
this.metadataType = '';
|
||||
this.metadataMessage = '';
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,187 @@
|
|||
<template>
|
||||
<div>
|
||||
<b-datepicker
|
||||
v-model="dateInit"
|
||||
:aria-labelledby="'filter-label-id-' + filter.id"
|
||||
:placeholder="$i18n.get('label_selectbox_init')"
|
||||
editable
|
||||
:trap-focus="false"
|
||||
:date-formatter="(date) => dateFormatter(date)"
|
||||
:date-parser="(date) => dateParser(date)"
|
||||
icon="calendar-today"
|
||||
:years-range="[-200, 100]"
|
||||
:day-names="[
|
||||
$i18n.get('datepicker_short_sunday'),
|
||||
$i18n.get('datepicker_short_monday'),
|
||||
$i18n.get('datepicker_short_tuesday'),
|
||||
$i18n.get('datepicker_short_wednesday'),
|
||||
$i18n.get('datepicker_short_thursday'),
|
||||
$i18n.get('datepicker_short_friday'),
|
||||
$i18n.get('datepicker_short_saturday'),
|
||||
]"
|
||||
@focus="isTouched = true"
|
||||
@update:model-value="($event) => { resetPage(); validadeValues($event) }" />
|
||||
<p
|
||||
style="font-size: 0.75em; margin-bottom: 0.125em;"
|
||||
class="has-text-centered is-marginless">
|
||||
{{ $i18n.get('label_until') }}
|
||||
</p>
|
||||
<b-datepicker
|
||||
v-model="dateEnd"
|
||||
:aria-labelledby="'filter-label-id-' + filter.id"
|
||||
:placeholder="$i18n.get('label_selectbox_init')"
|
||||
editable
|
||||
:trap-focus="false"
|
||||
:date-formatter="(date) => dateFormatter(date)"
|
||||
:date-parser="(date) => dateParser(date)"
|
||||
icon="calendar-today"
|
||||
:years-range="[-200, 50]"
|
||||
:day-names="[
|
||||
$i18n.get('datepicker_short_sunday'),
|
||||
$i18n.get('datepicker_short_monday'),
|
||||
$i18n.get('datepicker_short_tuesday'),
|
||||
$i18n.get('datepicker_short_wednesday'),
|
||||
$i18n.get('datepicker_short_thursday'),
|
||||
$i18n.get('datepicker_short_friday'),
|
||||
$i18n.get('datepicker_short_saturday'),
|
||||
]"
|
||||
@update:model-value="validadeValues()"
|
||||
@focus="isTouched = true" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { dateInter } from "../../../js/mixins";
|
||||
import { filterTypeMixin } from '../../../js/filter-types-mixin';
|
||||
import moment from 'moment';
|
||||
|
||||
export default {
|
||||
mixins: [
|
||||
dateInter,
|
||||
filterTypeMixin
|
||||
],
|
||||
emits: [
|
||||
'input',
|
||||
],
|
||||
data(){
|
||||
return {
|
||||
dateInit: undefined,
|
||||
dateEnd: undefined,
|
||||
isTouched: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
isTouched( val ){
|
||||
if ( val && this.dateInit === null)
|
||||
this.dateInit = new Date();
|
||||
|
||||
if ( val && this.dateEnd === null)
|
||||
this.dateEnd = new Date();
|
||||
},
|
||||
'query': {
|
||||
handler() {
|
||||
this.updateSelectedValues();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateSelectedValues();
|
||||
},
|
||||
methods: {
|
||||
// only validate if the first value is higher than first
|
||||
validadeValues: _.debounce( function (){
|
||||
|
||||
if (this.dateInit === undefined)
|
||||
this.dateInit = new Date();
|
||||
|
||||
if (this.dateEnd === undefined)
|
||||
this.dateEnd = new Date();
|
||||
|
||||
if (this.dateInit > this.dateEnd) {
|
||||
this.showErrorMessage();
|
||||
return
|
||||
}
|
||||
|
||||
this.emit();
|
||||
}, 800),
|
||||
showErrorMessage(){
|
||||
if ( !this.isTouched ) return false;
|
||||
|
||||
this.$buefy.toast.open({
|
||||
duration: 3000,
|
||||
message: this.$i18n.get('info_error_first_value_greater'),
|
||||
position: 'is-bottom',
|
||||
type: 'is-danger'
|
||||
})
|
||||
},
|
||||
dateFormatter(dateObject){
|
||||
return moment(dateObject, moment.ISO_8601).format(this.dateFormat);
|
||||
},
|
||||
dateParser(dateString){
|
||||
return moment(dateString, this.dateFormat).toDate();
|
||||
},
|
||||
updateSelectedValues(){
|
||||
if ( !this.query || !this.query.metaquery || !Array.isArray( this.query.metaquery ) )
|
||||
return false;
|
||||
|
||||
let index = this.query.metaquery.findIndex(newMetadatum => newMetadatum.key == this.metadatumId);
|
||||
|
||||
if (index >= 0) {
|
||||
let metadata = this.query.metaquery[ index ];
|
||||
if (metadata.value && metadata.value.length > 0) {
|
||||
const dateValueInit = new Date(metadata.value[0].replace(/-/g, '/'));
|
||||
this.dateInit = moment(dateValueInit, moment.ISO_8601).toDate();
|
||||
const dateValueEnd = new Date(metadata.value[1].replace(/-/g, '/'));
|
||||
this.dateEnd = moment(dateValueEnd, moment.ISO_8601).toDate();
|
||||
}
|
||||
} else {
|
||||
this.dateInit = null;
|
||||
this.dateEnd = null;
|
||||
}
|
||||
},
|
||||
// emit the operation for listeners
|
||||
emit() {
|
||||
let values = [];
|
||||
|
||||
if (this.dateInit === null && this.dateEnd === null) {
|
||||
values = [];
|
||||
} else {
|
||||
let dateInit = this.dateInit.getUTCFullYear() + '-' +
|
||||
('00' + (this.dateInit.getUTCMonth() + 1)).slice(-2) + '-' +
|
||||
('00' + this.dateInit.getUTCDate()).slice(-2);
|
||||
let dateEnd = this.dateEnd.getUTCFullYear() + '-' +
|
||||
('00' + (this.dateEnd.getUTCMonth() + 1)).slice(-2) + '-' +
|
||||
('00' + this.dateEnd.getUTCDate()).slice(-2);
|
||||
values = [ dateInit, dateEnd ];
|
||||
}
|
||||
|
||||
this.$emit('input', {
|
||||
filter: 'intersection',
|
||||
type: 'DATE',
|
||||
compare: '>=',
|
||||
metadatum_id: this.metadatumId,
|
||||
collection_id: this.collectionId,
|
||||
value: values
|
||||
});
|
||||
this.$emit('input', {
|
||||
filter: 'intersection',
|
||||
type: 'DATE',
|
||||
compare: '<=',
|
||||
metadatum_id: this.filterTypeOptions.secondary_filter_metadatum_id,
|
||||
collection_id: this.collectionId,
|
||||
value: values
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.field {
|
||||
margin-bottom: 0.125em !important;
|
||||
}
|
||||
.dropdown-trigger input {
|
||||
font-size: 0.75em;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
namespace Tainacan\Filter_Types;
|
||||
|
||||
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
|
||||
|
||||
/**
|
||||
* Class TainacanFilterType
|
||||
*/
|
||||
class Dates_Intersection extends Filter_Type {
|
||||
|
||||
function __construct(){
|
||||
$this->set_name( __('Dates Intersection', 'tainacan') );
|
||||
$this->set_supported_types(['date']);
|
||||
$this->set_component('tainacan-filter-dates-intersection');
|
||||
$this->set_form_component('tainacan-filter-form-dates-intersection');
|
||||
$this->set_default_options([
|
||||
'secondary_filter_metadatum_id' => '',
|
||||
'secondary_filter_metadatum_name' => '',
|
||||
]);
|
||||
$this->set_use_max_options(false);
|
||||
$this->set_preview_template('
|
||||
<div>
|
||||
<div class="datepicker control is-small">
|
||||
<div class="dropdown is-bottom-left is-mobile-modal">
|
||||
<div role="button" class="dropdown-trigger">
|
||||
<div class="control has-icons-left is-small is-clearfix">
|
||||
<input type="text" autocomplete="off" placeholder=" '. __('Select a date', 'tainacan') .'" class="input is-small">
|
||||
<span class="icon is-left is-small"><i class="mdi mdi-calendar-today"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="is-size-7 has-text-centered is-marginless">until</p>
|
||||
<div class="datepicker control is-small">
|
||||
<div class="dropdown is-bottom-left is-mobile-modal">
|
||||
<div role="button" class="dropdown-trigger">
|
||||
<div class="control has-icons-left is-small is-clearfix">
|
||||
<input type="text" autocomplete="off" placeholder=" '. __('Select a date', 'tainacan') .'" class="input is-small">
|
||||
<span class="icon is-left is-small"><i class="mdi mdi-calendar-today"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function get_form_labels(){
|
||||
return [
|
||||
'secondary_filter_metadatum_id' => [
|
||||
'title' => __( 'Second date metadatum', 'tainacan' ),
|
||||
'description' => __( 'The other metadatum to which this filter will compare values to find if there is an intersection of dates.', 'tainacan' ),
|
||||
],
|
||||
'secondary_filter_metadatum_name' => [
|
||||
'title' => __( 'Second date metadatum', 'tainacan' ),
|
||||
'description' => __( 'Label of the other metadatum to which this filter will compare values to find if there is an intersection of dates.', 'tainacan' ),
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Tainacan\Entities\Filter $filter
|
||||
* @return array|bool true if is validate or array if has error
|
||||
*/
|
||||
public function validate_options(\Tainacan\Entities\Filter $filter) {
|
||||
if ( !in_array($filter->get_status(), apply_filters('tainacan-status-require-validation', ['publish','future','private'])) )
|
||||
return true;
|
||||
|
||||
if ( empty($this->get_option('secondary_filter_metadatum_id')) ) {
|
||||
return [
|
||||
'secondary_filter_metadatum_id' => __('The secondary date metadatum is required.','tainacan')
|
||||
];
|
||||
}
|
||||
|
||||
// Validate if the second date metadatum is a date metadatum
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Dates_Intersection_Interval_Helper {
|
||||
use \Tainacan\Traits\Singleton_Instance;
|
||||
|
||||
protected function init() {
|
||||
add_filter( 'tainacan-api-items-tainacan-filter-dates-intersection-filter-arguments', [$this, 'format_filter_arguments']);
|
||||
}
|
||||
|
||||
function format_filter_arguments( $filter_arguments ) {
|
||||
if (
|
||||
!isset($filter_arguments['compare']) ||
|
||||
!isset($filter_arguments['label'])
|
||||
) {
|
||||
return $filter_arguments;
|
||||
}
|
||||
|
||||
if (
|
||||
is_array($filter_arguments['label']) &&
|
||||
count($filter_arguments['label']) === 2
|
||||
) {
|
||||
$filter_arguments['label'] = $filter_arguments['label'][0] . ' - ' . $filter_arguments['label'][1];
|
||||
}
|
||||
if (
|
||||
isset( $filter_arguments['filter'] ) &&
|
||||
isset( $filter_arguments['filter']['filter_type_options'] ) &&
|
||||
isset( $filter_arguments['filter']['filter_type_options']['secondary_filter_metadatum_name'] ) &&
|
||||
!empty( $filter_arguments['filter']['filter_type_options']['secondary_filter_metadatum_name'] )
|
||||
) {
|
||||
$filter_arguments['filter']['name'] = $filter_arguments['filter']['name'] . ' - ' . $filter_arguments['filter']['filter_type_options']['secondary_filter_metadatum_name'];
|
||||
}
|
||||
return $filter_arguments;
|
||||
}
|
||||
}
|
||||
Dates_Intersection_Interval_Helper::get_instance();
|
|
@ -38,6 +38,7 @@ class Filter_Type_Helper {
|
|||
$this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Selectbox');
|
||||
$this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Autocomplete');
|
||||
$this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Date_Interval');
|
||||
$this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Dates_Intersection');
|
||||
$this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Numeric_Interval');
|
||||
$this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\TaxonomyTaginput');
|
||||
$this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\TaxonomyCheckbox');
|
||||
|
|
|
@ -100,6 +100,7 @@
|
|||
TainacanFilterTaxonomyCheckbox: defineAsyncComponent(() => import('./taxonomy/TainacanFilterCheckbox.vue')),
|
||||
TainacanFilterTaxonomyTaginput: defineAsyncComponent(() => import('./taxonomy/TainacanFilterTaginput.vue')),
|
||||
TainacanFilterDateInterval: defineAsyncComponent(() => import('./date-interval/TainacanFilterDateInterval.vue')),
|
||||
TainacanFilterDatesIntersection: defineAsyncComponent(() => import('./dates-intersection/TainacanFilterDatesIntersection.vue')),
|
||||
TainacanFilterNumericInterval: defineAsyncComponent(() => import('./numeric-interval/TainacanFilterNumericInterval.vue')),
|
||||
TainacanFilterNumericListInterval: defineAsyncComponent(() => import('./numeric-list-interval/TainacanFilterNumericListInterval.vue'))
|
||||
},
|
||||
|
|
|
@ -788,6 +788,7 @@ return apply_filters( 'tainacan-i18n', [
|
|||
'instruction_click_to_add_a_point' => __( 'Drag to reposition or click to insert a marker', 'tainacan' ),
|
||||
'instruction_select_geocoordinate_metadatum' => __( 'Select a geocoordinate metadatum', 'tainacan' ),
|
||||
'instruction_multiple_terms_insertion' => __( 'Type or paste here a list of names using a separator to create multiple terms at once.', 'tainacan' ),
|
||||
'instruction_select_second_date_to_compare' => __( 'Select the second date metadatum', 'tainacan' ),
|
||||
|
||||
// Info. Other feedback to user.
|
||||
'info_items_tab_all' => __( 'Every item, except by those sent to trash.', 'tainacan' ),
|
||||
|
|
Loading…
Reference in New Issue