Merge branch 'release/0.21.7'

This commit is contained in:
vnmedeiros 2024-07-01 15:47:28 -03:00
commit 28f0ec5a5f
99 changed files with 3739 additions and 574 deletions

View File

@ -55,6 +55,24 @@
flex-wrap: nowrap; flex-wrap: nowrap;
flex-direction: row; flex-direction: row;
flex: 1 0 auto; } flex: 1 0 auto; }
.wp-block-tainacan-faceted-search .items-list-placeholder .below-search-control.horizontal-filters {
flex-direction: column; }
.wp-block-tainacan-faceted-search .items-list-placeholder .below-search-control.horizontal-filters .filters {
flex-direction: row;
flex: 0 1 100%;
flex-wrap: wrap;
padding: 18px 12px 6px 12px; }
.wp-block-tainacan-faceted-search .items-list-placeholder .below-search-control.horizontal-filters .filters .fake-filters-heading {
margin-right: 90%;
top: -0.5em;
left: 0.5em; }
.wp-block-tainacan-faceted-search .items-list-placeholder .below-search-control.horizontal-filters .filters .fake-filters-heading + .fake-link {
margin-right: 95%;
margin-left: 12px; }
.wp-block-tainacan-faceted-search .items-list-placeholder .below-search-control.horizontal-filters .filters .fake-filter {
margin: 6px 12px;
display: inline-flex;
width: var(--tainacan-filters-inline-width, 272px); }
.wp-block-tainacan-faceted-search .items-list-placeholder .below-search-control .filters { .wp-block-tainacan-faceted-search .items-list-placeholder .below-search-control .filters {
flex: 0 1 var(--tainacan-filter-menu-width-theme, 20%); flex: 0 1 var(--tainacan-filter-menu-width-theme, 20%);
display: flex; display: flex;
@ -64,7 +82,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 80%; width: 80%;
margin: 5% 12%; } margin: 5% 8%; }
.wp-block-tainacan-faceted-search .items-list-placeholder .below-search-control .filters .fake-filter .fake-text { .wp-block-tainacan-faceted-search .items-list-placeholder .below-search-control .filters .fake-filter .fake-text {
margin: 4px 0; margin: 4px 0;
width: 35%; width: 35%;

File diff suppressed because one or more lines are too long

View File

@ -454,7 +454,7 @@ class REST_Items_Controller extends REST_Controller {
* @return array * @return array
* @throws \Exception * @throws \Exception
*/ */
private function prepare_filters_arguments ( $args, $collection_id = false ) { private function prepare_filters_arguments ( $args, $collection_id = false, $ignore_filter_arguments = [] ) {
$filters_arguments = array(); $filters_arguments = array();
$meta_query = isset($args['meta_query']) ? $args['meta_query'] : []; $meta_query = isset($args['meta_query']) ? $args['meta_query'] : [];
if(isset($meta_query['value'])) $meta_query = [$meta_query]; if(isset($meta_query['value'])) $meta_query = [$meta_query];
@ -498,8 +498,7 @@ class REST_Items_Controller extends REST_Controller {
} }
foreach($meta_query as $meta) { foreach($meta_query as $meta) {
if ( !isset($meta['key']) || !isset($meta['value']) || ( in_array($meta['key'], $ignore_filter_arguments) ))
if ( !isset($meta['key']) || !isset($meta['value']) )
continue; continue;
$meta_id = $meta['key']; $meta_id = $meta['key'];
@ -554,6 +553,7 @@ class REST_Items_Controller extends REST_Controller {
$date_format = get_option( 'date_format' ) != false ? get_option( 'date_format' ) : 'Y-m-d'; $date_format = get_option( 'date_format' ) != false ? get_option( 'date_format' ) : 'Y-m-d';
return empty($date) == false ? mysql2date($date_format, $date) : ""; return empty($date) == false ? mysql2date($date_format, $date) : "";
}, $meta_label); }, $meta_label);
$meta_type = 'DATE';
break; break;
case 'item': case 'item':
$meta_label = array_map(function($item_id) { $meta_label = array_map(function($item_id) {
@ -643,7 +643,15 @@ class REST_Items_Controller extends REST_Controller {
if($request['collection_id']) { if($request['collection_id']) {
$collection_id = $request['collection_id']; $collection_id = $request['collection_id'];
} }
$filters_args = $this->prepare_filters_arguments($args, $collection_id); $metaqueries = isset($request['metaquery']) ? $request['metaquery'] : [];
$ignore_filter_arguments = array_map(
function($metaquery) { return $metaquery['key']; },
array_filter(
$metaqueries,
function($metaquery) { return isset($metaquery['key']) && isset($metaquery['secondary']) && $metaquery['secondary'] == 'true'; }
)
);
$filters_args = $this->prepare_filters_arguments($args, $collection_id, $ignore_filter_arguments);
if(isset($args['meta_query']) && !empty($args['meta_query']) && is_array($filters_args) && !empty($filters_args)) { if(isset($args['meta_query']) && !empty($args['meta_query']) && is_array($filters_args) && !empty($filters_args)) {
foreach($filters_args as $filters_arg) { foreach($filters_args as $filters_arg) {
if($filters_arg['filter'] !== false) { if($filters_arg['filter'] !== false) {

View File

@ -20,7 +20,8 @@ class Filter extends Entity {
$filter_type, $filter_type,
$filter_type_options, $filter_type_options,
$begin_with_filter_collapsed, $begin_with_filter_collapsed,
$display_in_repository_level_lists; $display_in_repository_level_lists,
$description_bellow_name;
static $post_type = 'tainacan-filter'; static $post_type = 'tainacan-filter';
public $enabled_for_collection = true; public $enabled_for_collection = true;
@ -76,6 +77,13 @@ class Filter extends Entity {
return $this->get_mapped_property('description'); return $this->get_mapped_property('description');
} }
/**
* @return mixed|null
*/
function get_placeholder() {
return $this->get_mapped_property('placeholder');
}
/** /**
* Return the filter order type * Return the filter order type
* *
@ -189,6 +197,14 @@ class Filter extends Entity {
return $this->get_mapped_property('display_in_repository_level_lists'); return $this->get_mapped_property('display_in_repository_level_lists');
} }
/**
* Return the filter description_bellow_name
*
* @return string
*/
function get_description_bellow_name() {
return $this->get_mapped_property('description_bellow_name');
}
/** /**
* Define the filter name * Define the filter name
@ -220,6 +236,16 @@ class Filter extends Entity {
$this->set_mapped_property('description', $value); $this->set_mapped_property('description', $value);
} }
/**
* Define the filter placeholder
*
* @param [string] $value
* @return void
*/
function set_placeholder($value) {
$this->set_mapped_property('placeholder', $value);
}
/** /**
* Define the filter metadatum passing an object * Define the filter metadatum passing an object
* *
@ -284,6 +310,16 @@ class Filter extends Entity {
$this->enabled_for_collection = $value; $this->enabled_for_collection = $value;
} }
/**
* Set filter description_bellow_name
*
* @param [string] $value If the description will be displayed below the name instead of inside a tooltip (yes/no)
* @return void
*/
function set_description_bellow_name($value) {
$this->set_mapped_property('description_bellow_name', $value);
}
/** /**
* {@inheritdoc } * {@inheritdoc }

View File

@ -697,6 +697,7 @@ class CSV extends Importer {
remove_action( 'post_updated', 'wp_save_post_revision' ); remove_action( 'post_updated', 'wp_save_post_revision' );
$collections = $this->get_collections(); $collections = $this->get_collections();
$collection_definition = isset($collections[$collection_index]) ? $collections[$collection_index] : false; $collection_definition = isset($collections[$collection_index]) ? $collections[$collection_index] : false;
if ( !$collection_definition || !is_array($collection_definition) || !isset($collection_definition['id']) || !isset($collection_definition['mapping']) ) { if ( !$collection_definition || !is_array($collection_definition) || !isset($collection_definition['id']) || !isset($collection_definition['mapping']) ) {
$this->add_error_log('Collection misconfigured'); $this->add_error_log('Collection misconfigured');
return false; return false;
@ -712,7 +713,7 @@ class CSV extends Importer {
$Tainacan_Metadata = \Tainacan\Repositories\Metadata::get_instance(); $Tainacan_Metadata = \Tainacan\Repositories\Metadata::get_instance();
$Tainacan_Item_Metadata = \Tainacan\Repositories\Item_Metadata::get_instance(); $Tainacan_Item_Metadata = \Tainacan\Repositories\Item_Metadata::get_instance();
$Tainacan_Items = \Tainacan\Repositories\Items::get_instance(); $Tainacan_Items = \Tainacan\Repositories\Items::get_instance();
$special_columns = false;
$itemMetadataArray = []; $itemMetadataArray = [];
@ -820,7 +821,17 @@ class CSV extends Importer {
} }
} }
if( (!empty( $itemMetadataArray ) || $special_columns) && $collection instanceof Entities\Collection ) { if ( !( $collection instanceof Entities\Collection ) ) {
$this->add_error_log( 'Collection not set');
return false;
}
if ( ( empty( $itemMetadataArray ) && !$special_columns ) ) {
$this->add_log( 'Found one empty value' );
return false;
}
$item->set_collection( $collection ); $item->set_collection( $collection );
if ( !$updating_item ) { if ( !$updating_item ) {
if( $item->validate() ) { if( $item->validate() ) {
@ -833,8 +844,10 @@ class CSV extends Importer {
} else { } else {
$insertedItem = $item; $insertedItem = $item;
} }
global $wpdb; global $wpdb;
$wpdb->query( 'SET autocommit = 0;' ); $wpdb->query( 'SET autocommit = 0;' );
foreach ( $itemMetadataArray as $itemMetadata ) { foreach ( $itemMetadataArray as $itemMetadata ) {
if($itemMetadata instanceof Entities\Item_Metadata_Entity ) { if($itemMetadata instanceof Entities\Item_Metadata_Entity ) {
$itemMetadata->set_item( $insertedItem ); // *I told you $itemMetadata->set_item( $insertedItem ); // *I told you
@ -891,10 +904,6 @@ class CSV extends Importer {
return false; return false;
} }
return $insertedItem; return $insertedItem;
} else {
$this->add_error_log( 'Collection not set');
return false;
}
} }
private function is_assoc(array $arr) { private function is_assoc(array $arr) {

View File

@ -132,7 +132,7 @@ class Collections extends Repository {
'title' => __( 'Enabled view modes', 'tainacan' ), 'title' => __( 'Enabled view modes', 'tainacan' ),
'type' => 'array', 'type' => 'array',
'description' => __( 'Which visualization modes will be available for the public to choose from', 'tainacan' ), 'description' => __( 'Which visualization modes will be available for the public to choose from', 'tainacan' ),
'default' => [ 'table', 'cards' ], 'default' => [ 'table', 'cards', 'masonry' ],
'items' => [ 'type' => 'string' ], 'items' => [ 'type' => 'string' ],
//'validation' => v::stringType(), //'validation' => v::stringType(),
], ],

View File

@ -110,7 +110,24 @@ class Filters extends Repository {
'description' => __( 'The max number of options to be showed in filter sidebar.', 'tainacan' ), 'description' => __( 'The max number of options to be showed in filter sidebar.', 'tainacan' ),
'validation' => '', 'validation' => '',
'default' => 4 'default' => 4
] ],
'placeholder' => [
'map' => 'meta',
'title' => __( 'Placeholder', 'tainacan' ),
'type' => 'string',
'description' => __( 'The filter input placeholder. This is a simple message that will appear inside textual input and may indicate to the user what kind of information is expected.', 'tainacan' ),
'default' => '',
],
'description_bellow_name' => [
'map' => 'meta',
'title' => __( 'Description below name', 'tainacan' ),
'type' => 'string',
'description' => __( 'Whether the filter description should be displayed below the input label instead of inside a tooltip.', 'tainacan' ),
'on_error' => __( 'Please set the "Description below name" value as "yes" or "no"', 'tainacan' ),
'validation' => v::stringType()->in( [ 'yes', 'no' ] ), // yes or no
'enum' => [ 'yes', 'no' ],
'default' => 'no'
],
] ); ] );
} }

View File

@ -37,7 +37,7 @@ class Theme_Helper {
// Replace collections permalink to post type archive if cover not enabled // Replace collections permalink to post type archive if cover not enabled
add_filter('post_type_link', array($this, 'permalink_filter'), 10, 3); add_filter('post_type_link', array($this, 'permalink_filter'), 10, 3);
// Replace single query to the page content set as cover for the colllection // Replace single query to the page content set as cover for the collection
// Redirect to post type archive if no cover page is set // Redirect to post type archive if no cover page is set
add_action('wp', array($this, 'collection_single_redirect')); add_action('wp', array($this, 'collection_single_redirect'));
@ -512,6 +512,9 @@ class Theme_Helper {
* @type string $default_view_mode The default view mode * @type string $default_view_mode The default view mode
* @type bool $is_forced_view_mode Ignores user prefs to always render the choosen default view mode * @type bool $is_forced_view_mode Ignores user prefs to always render the choosen default view mode
* @type string[] $enabled_view_modes The list os enable view modes to display * @type string[] $enabled_view_modes The list os enable view modes to display
* @type bool $should_not_hide_filters_on_mobile Disables the default behavior of automatically collapsing the filters inside a modal when in small screen sizes
* @type bool $display_filters_horizontally Display the filters in an horizontal panel above search control instead of a sidebar
* @type bool $hide_filter_collapses Hides the button that collapses all filters inside the filters panel
* @return string The HTML div to be used for rendering the items list vue component * @return string The HTML div to be used for rendering the items list vue component
*/ */
public function search_shortcode($args) { public function search_shortcode($args) {
@ -617,7 +620,10 @@ class Theme_Helper {
'data-start-with-filters-hidden' => true, 'data-start-with-filters-hidden' => true,
'data-filters-as-modal' => true, 'data-filters-as-modal' => true,
'data-show-inline-view-mode-options' => true, 'data-show-inline-view-mode-options' => true,
'data-show-fullscreen-with-view-modes' => true 'data-show-fullscreen-with-view-modes' => true,
'data-should-not-hide-filters-on-mobile' => true,
'data-display-filters-horizontally' => true,
'data-hide-filter-collapses' => true
] ]
]; ];
@ -2479,5 +2485,23 @@ class Theme_Helper {
'requires_thumbnail' => false, 'requires_thumbnail' => false,
'placeholder_template' => $map_view_mode_placeholder 'placeholder_template' => $map_view_mode_placeholder
]); ]);
$this->register_view_mode('mosaic', [
'label' => __('Mosaic', 'tainacan'),
'dynamic_metadata' => false,
'description' => __('A mosaic view, similar to Flickr and Google Photos, which will display images without cropping.', 'tainacan'),
'icon' => '<span class="icon"><i class="tainacan-icon tainacan-icon-viewmasonry tainacan-icon-rotate-90 tainacan-icon-1-25em"></i></span>',
'type' => 'component',
'implements_skeleton' => true,
'placeholder_template' => '<ul style="list-style: none;width: 100%; height: auto; display: flex; gap: 24px 0; flex-wrap: wrap;">' .
array_reduce( range(0,11), function($container, $i) {
$container .= '<li style="flex-grow: 1; max-width: 35%; width: ' . ($i % 2 == 0 ? rand(100, 180) : rand(90, 170)) . 'px; height: 120px ; background-color: var(--tainacan-block-gray1, #f2f2f2); margin: 0; padding: 5px;">
<div style="width: 100%;height: 100%; background-color: var(--tainacan-block-gray2, #dbdbdb);margin-bottom: 10px;"></div>
<div style="width: 100%;height: 10px; background-color: var(--tainacan-block-gray3, #a5a5a5);"></div>
</li>';
return $container;
}) .
'</ul>'
]);
} }
} }

View File

@ -4,7 +4,7 @@ Tags: museums, archives, GLAM, collections, repository
Requires at least: 5.9 Requires at least: 5.9
Tested up to: 6.5 Tested up to: 6.5
Requires PHP: 7.0 Requires PHP: 7.0
Stable tag: 0.21.6 Stable tag: 0.21.7
License: GPLv2 or later License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html License URI: http://www.gnu.org/licenses/gpl-3.0.html

View File

@ -5,17 +5,17 @@ Plugin URI: https://tainacan.org/
Description: Open source, 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. Description: Open source, 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.
Author: Tainacan.org Author: Tainacan.org
Author URI: https://tainacan.org/ Author URI: https://tainacan.org/
Version: 0.21.6 Version: 0.21.7
Requires at least: 5.9 Requires at least: 5.9
Tested up to: 6.5 Tested up to: 6.5
Requires PHP: 7.0 Requires PHP: 7.0
Stable tag: 0.21.6 Stable tag: 0.21.7
Text Domain: tainacan Text Domain: tainacan
License: GPLv2 or later License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-3.0.html License URI: http://www.gnu.org/licenses/gpl-3.0.html
*/ */
const TAINACAN_VERSION = '0.21.6'; const TAINACAN_VERSION = '0.21.7';
defined( 'ABSPATH' ) or die( 'No script kiddies please!' ); defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
$TAINACAN_BASE_URL = plugins_url('', __FILE__); $TAINACAN_BASE_URL = plugins_url('', __FILE__);

View File

@ -5,6 +5,7 @@
:class="{ :class="{
'tainacan-admin-mobile-app-mode': $adminOptions.mobileAppMode 'tainacan-admin-mobile-app-mode': $adminOptions.mobileAppMode
}"> }">
<template v-if="hasPermalinksStructure">
<template v-if="activeRoute == 'HomePage'"> <template v-if="activeRoute == 'HomePage'">
<tainacan-header v-if="!$adminOptions.hideTainacanHeader" /> <tainacan-header v-if="!$adminOptions.hideTainacanHeader" />
<router-view /> <router-view />
@ -46,6 +47,7 @@
<router-view /> <router-view />
</div> </div>
</template> </template>
</template>
</div> </div>
</template> </template>
@ -70,7 +72,8 @@
return { return {
isMenuCompressed: false, isMenuCompressed: false,
isRepositoryLevel : true, isRepositoryLevel : true,
activeRoute: '/collections' activeRoute: '/collections',
hasPermalinksStructure: false
} }
}, },
computed: { computed: {
@ -105,6 +108,10 @@
} }
}, },
created() { created() {
this.hasPermalinksStructure = tainacan_plugin.has_permalinks_structure;
if ( this.hasPermalinksStructure ) {
this.$statusHelper.loadStatuses(); this.$statusHelper.loadStatuses();
this.$userPrefs.init(); this.$userPrefs.init();
this.isMenuCompressed = (this.$route.params.collectionId != undefined); this.isMenuCompressed = (this.$route.params.collectionId != undefined);
@ -114,10 +121,31 @@
if (jQuery && jQuery( document )) { if (jQuery && jQuery( document )) {
jQuery( document ).ajaxError(this.onHeartBitError); jQuery( document ).ajaxError(this.onHeartBitError);
} }
} else {
this.onPermalinksError();
}
}, },
methods: { methods: {
onPermalinksError() {
this.$buefy.modal.open({
component: CustomDialog,
props: {
title: this.$i18n.get('error_permalinks_label'),
message: this.$i18n.getWithVariables('error_permalinks_detail', [ '<a href="' + tainacan_plugin.admin_url + 'options-permalink.php">', '</a>' ]),
hideCancel: true,
confirmText: this.$i18n.get('label_go_to_permalinks'),
onConfirm: () => {
window.location.href = tainacan_plugin.admin_url + 'options-permalink.php';
}
},
ariaRole: 'alertdialog',
ariaModal: true,
customClass: 'tainacan-modal',
canCancel: false,
});
},
onHeartBitError(event, jqxhr, settings) { onHeartBitError(event, jqxhr, settings) {
if (settings && settings.url == '/wp-admin/admin-ajax.php') { if (settings && settings.url == tainacan_plugin.admin_url + 'admin-ajax.php') {
this.$buefy.snackbar.open({ this.$buefy.snackbar.open({
message: this.$i18n.get('error_connectivity'), message: this.$i18n.get('error_connectivity'),
type: 'is-danger', type: 'is-danger',

View File

@ -49,6 +49,45 @@
@focus="clearErrors('description')" /> @focus="clearErrors('description')" />
</b-field> </b-field>
<b-field
:addons="false"
:label="$i18n.getHelperTitle('filters', 'description_bellow_name')"
:type="formErrors['description_bellow_name'] != undefined ? 'is-danger' : ''"
:message="formErrors['description_bellow_name'] != undefined ? formErrors['description_bellow_name'] : ''">
&nbsp;
<b-switch
v-model="form.description_bellow_name"
size="is-small"
true-value="yes"
false-value="no"
:native-value="form.description_bellow_name == 'yes' ? 'yes' : 'no'"
name="description_bellow_name"
@update:model-value="clearErrors('description_bellow_name')">
<help-button
:title="$i18n.getHelperTitle('filters', 'description_bellow_name')"
:message="$i18n.getHelperMessage('filters', 'description_bellow_name')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</b-switch>
</b-field>
<b-field
v-if="form.filter_type_object.use_input_placeholder"
:addons="false"
:type="formErrors['placeholder'] != undefined ? 'is-danger' : ''"
:message="formErrors['placeholder'] != undefined ? formErrors['placeholder'] : ''">
<label class="label is-inline">
{{ $i18n.getHelperTitle('filters', 'placeholder') }}
<help-button
:title="$i18n.getHelperTitle('filters', 'placeholder')"
:message="$i18n.getHelperMessage('filters', 'placeholder')"
:extra-classes="isRepositoryLevel ? 'tainacan-repository-tooltip' : ''" />
</label>
<b-input
v-model="form.placeholder"
name="placeholder"
@focus="clearErrors('placeholder')" />
</b-field>
<b-field <b-field
:addons="false" :addons="false"
:type="formErrors['status'] != undefined ? 'is-danger' : ''" :type="formErrors['status'] != undefined ? 'is-danger' : ''"
@ -249,16 +288,22 @@ import { nextTick } from 'vue';
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import { formHooks } from "../../js/mixins"; import { formHooks } from "../../js/mixins";
import FormFilterDate from '../filter-types/date/FormDate.vue';
import FormFilterNumeric from '../filter-types/numeric/FormNumeric.vue'; import FormFilterNumeric from '../filter-types/numeric/FormNumeric.vue';
import FormFilterNumericInterval from '../filter-types/numeric-interval/FormNumericInterval.vue'; import FormFilterNumericInterval from '../filter-types/numeric-interval/FormNumericInterval.vue';
import FormFilterNumericListInterval from '../filter-types/numeric-list-interval/FormNumericListInterval.vue'; import FormFilterNumericListInterval from '../filter-types/numeric-list-interval/FormNumericListInterval.vue';
import FormFilterNumericsIntersection from '../filter-types/numerics-intersection/FormNumericsIntersection.vue';
import FormFilterDatesIntersection from '../filter-types/dates-intersection/FormDatesIntersection.vue';
export default { export default {
name: 'FilterEditionForm', name: 'FilterEditionForm',
components: { components: {
'tainacan-filter-form-date': FormFilterDate,
'tainacan-filter-form-numeric': FormFilterNumeric, 'tainacan-filter-form-numeric': FormFilterNumeric,
'tainacan-filter-form-numeric-interval': FormFilterNumericInterval, 'tainacan-filter-form-numeric-interval': FormFilterNumericInterval,
'tainacan-filter-form-numeric-list-interval': FormFilterNumericListInterval 'tainacan-filter-form-numeric-list-interval': FormFilterNumericListInterval,
'tainacan-filter-form-numerics-intersection': FormFilterNumericsIntersection,
'tainacan-filter-form-dates-intersection': FormFilterDatesIntersection
}, },
mixins: [ formHooks ], mixins: [ formHooks ],
props: { props: {
@ -292,6 +337,10 @@ export default {
this.formErrorMessage = this.form.formErrors != undefined ? this.form.formErrorMessage : ''; this.formErrorMessage = this.form.formErrors != undefined ? this.form.formErrorMessage : '';
this.oldForm = JSON.parse(JSON.stringify(this.originalFilter)); this.oldForm = JSON.parse(JSON.stringify(this.originalFilter));
if ( this.form.metadatum == undefined && this.oldForm.metadatum != undefined )
this.form.metadatum = this.oldForm.metadatum;
}, },
mounted() { mounted() {
// Fills hook forms with it's real values // Fills hook forms with it's real values
@ -316,17 +365,21 @@ export default {
'updateFilter' 'updateFilter'
]), ]),
saveEdition(filter) { saveEdition(filter) {
if ((filter.filter_type_object && filter.filter_type_object.form_component) || filter.edit_form == '') {
this.isLoading = true; this.isLoading = true;
if ((filter.filter_type_object && filter.filter_type_object.form_component) || filter.edit_form == '') {
for (let [key, value] of Object.entries(this.form)) { for (let [key, value] of Object.entries(this.form)) {
if (key === 'begin_with_filter_collapsed' || key === 'display_in_repository_level_lists') if (key === 'begin_with_filter_collapsed' || key === 'display_in_repository_level_lists' || key === 'description_bellow_name' )
this.form[key] = (value == 'yes' || value == true) ? 'yes' : 'no'; this.form[key] = (value == 'yes' || value == true) ? 'yes' : 'no';
} }
if (this.form['begin_with_filter_collapsed'] === undefined) if (this.form['begin_with_filter_collapsed'] === undefined)
this.form['begin_with_filter_collapsed'] = 'no'; this.form['begin_with_filter_collapsed'] = 'no';
if (this.form['display_in_repository_level_lists'] === undefined) if (this.form['display_in_repository_level_lists'] === undefined)
this.form['display_in_repository_level_lists'] = 'no'; this.form['display_in_repository_level_lists'] = 'no';
if (this.form['description_bellow_name'] === undefined)
this.form['description_bellow_name'] = 'no';
this.updateFilter({ filterId: filter.id, index: this.index, options: this.form }) this.updateFilter({ filterId: filter.id, index: this.index, options: this.form })
.then(() => { .then(() => {
@ -355,7 +408,7 @@ export default {
let formObj = {}; let formObj = {};
for (let [key, value] of formData.entries()) { for (let [key, value] of formData.entries()) {
if (key === 'begin_with_filter_collapsed' || key === 'display_in_repository_level_lists') if (key === 'begin_with_filter_collapsed' || key === 'display_in_repository_level_lists' || key === 'description_bellow_name' )
formObj[key] = (value == 'yes' || value == true) ? 'yes' : 'no'; formObj[key] = (value == 'yes' || value == true) ? 'yes' : 'no';
else else
formObj[key] = value; formObj[key] = value;
@ -364,9 +417,10 @@ export default {
formObj['begin_with_filter_collapsed'] = 'no'; formObj['begin_with_filter_collapsed'] = 'no';
if (formObj['display_in_repository_level_lists'] === undefined) if (formObj['display_in_repository_level_lists'] === undefined)
formObj['display_in_repository_level_lists'] = 'no'; formObj['display_in_repository_level_lists'] = 'no';
if (formObj['description_bellow_name'] === undefined)
formObj['description_bellow_name'] = 'no';
this.fillExtraFormData(formObj); this.fillExtraFormData(formObj);
this.isLoading = true;
this.updateFilter({ filterId: filter.id, index: this.index, options: formObj }) this.updateFilter({ filterId: filter.id, index: this.index, options: formObj })
.then(() => { .then(() => {
this.form = {}; this.form = {};
@ -418,7 +472,7 @@ export default {
-webkit-column-gap: 0; -webkit-column-gap: 0;
-webkit-column-rule: none; -webkit-column-rule: none;
column-count: 2; column-count: 2;
column-gap: 4em; column-gap: 3em;
column-rule: none; column-rule: none;
padding-bottom: 0.5em; padding-bottom: 0.5em;

View File

@ -110,7 +110,7 @@
v-if="item.document != '' && item.document_type != 'empty'" v-if="item.document != '' && item.document_type != 'empty'"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_document_uploaded'), content: $i18n.get('label_document_uploaded'),
@ -128,7 +128,7 @@
<span <span
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_button_delete_document'), content: $i18n.get('label_button_delete_document'),

View File

@ -10,7 +10,7 @@
:loading="isLoadingOptions" :loading="isLoadingOptions"
field="label" field="label"
clearable clearable
:placeholder="(metadatumType === 'Tainacan\\Metadata_Types\\Relationship') ? $i18n.get('info_type_to_search_items') : $i18n.get('info_type_to_search_metadata')" :placeholder="filter.placeholder ? filter.placeholder : ( (metadatumType === 'Tainacan\\Metadata_Types\\Relationship') ? $i18n.get('info_type_to_search_items') : $i18n.get('info_type_to_search_metadata') )"
check-infinite-scroll check-infinite-scroll
@update:model-value="($event) => { resetPage(); search($event); }" @update:model-value="($event) => { resetPage(); search($event); }"
@select="onSelect" @select="onSelect"

View File

@ -19,10 +19,23 @@
@input="resetPage()"> @input="resetPage()">
<span class="check" /> <span class="check" />
<span class="control-label"> <span class="control-label">
<span class="checkbox-label-text">{{ option.label }}</span> <span
v-tooltip="{
delay: {
show: 800,
hide: 100,
},
content: option.label,
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''],
placement: 'auto-start'
}"
class="checkbox-label-text">
{{ option.label }}
</span>
<span <span
v-if="option.total_items != undefined" v-if="option.total_items != undefined"
class="has-text-gray">&nbsp;{{ "(" + option.total_items + ")" }}</span> class="facet-item-count has-text-gray">&nbsp;{{ "(" + option.total_items + ")" }}</span>
</span> </span>
</label> </label>
<button <button
@ -242,12 +255,26 @@
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: nowrap;
width: 100%; width: 100%;
align-items: center;
} }
.checkbox-label-text { .checkbox-label-text {
white-space: nowrap; white-space: wrap;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
line-height: 1.45em; line-height: 1.45em;
break-inside: avoid; break-inside: avoid;
display: -webkit-box;
line-clamp: 2;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
} }
.facet-item-count {
margin-left: auto;
}
.b-checkbox:hover .facet-item-count,
.b-checkbox:focus .facet-item-count {
--tainacan-info-color: var(--tainacan-input-color);
}
</style> </style>

View File

@ -12,6 +12,7 @@ class Checkbox extends Filter_Type {
$this->set_name( __('Checkbox List', 'tainacan') ); $this->set_name( __('Checkbox List', 'tainacan') );
$this->set_supported_types(['string','long_string','item', 'control']); $this->set_supported_types(['string','long_string','item', 'control']);
$this->set_component('tainacan-filter-checkbox'); $this->set_component('tainacan-filter-checkbox');
$this->set_use_input_placeholder(false);
$this->set_preview_template(' $this->set_preview_template('
<div> <div>
<div> <div>

View File

@ -3,7 +3,7 @@
<b-datepicker <b-datepicker
v-model="dateInit" v-model="dateInit"
:aria-labelledby="'filter-label-id-' + filter.id" :aria-labelledby="'filter-label-id-' + filter.id"
:placeholder="$i18n.get('label_selectbox_init')" :placeholder="filter.placeholder ? filter.placeholder : $i18n.get('instruction_select_a_date')"
editable editable
:trap-focus="false" :trap-focus="false"
:date-formatter="(date) => dateFormatter(date)" :date-formatter="(date) => dateFormatter(date)"
@ -19,6 +19,20 @@
$i18n.get('datepicker_short_friday'), $i18n.get('datepicker_short_friday'),
$i18n.get('datepicker_short_saturday'), $i18n.get('datepicker_short_saturday'),
]" ]"
:month-names="[
$i18n.get('datepicker_month_january'),
$i18n.get('datepicker_month_february'),
$i18n.get('datepicker_month_march'),
$i18n.get('datepicker_month_april'),
$i18n.get('datepicker_month_may'),
$i18n.get('datepicker_month_june'),
$i18n.get('datepicker_month_july'),
$i18n.get('datepicker_month_august'),
$i18n.get('datepicker_month_september'),
$i18n.get('datepicker_month_october'),
$i18n.get('datepicker_month_november'),
$i18n.get('datepicker_month_december')
]"
@focus="isTouched = true" @focus="isTouched = true"
@update:model-value="($event) => { resetPage(); validadeValues($event) }" /> @update:model-value="($event) => { resetPage(); validadeValues($event) }" />
<p <p
@ -29,7 +43,7 @@
<b-datepicker <b-datepicker
v-model="dateEnd" v-model="dateEnd"
:aria-labelledby="'filter-label-id-' + filter.id" :aria-labelledby="'filter-label-id-' + filter.id"
:placeholder="$i18n.get('label_selectbox_init')" :placeholder="filter.placeholder ? filter.placeholder : $i18n.get('instruction_select_a_date')"
editable editable
:trap-focus="false" :trap-focus="false"
:date-formatter="(date) => dateFormatter(date)" :date-formatter="(date) => dateFormatter(date)"
@ -45,6 +59,20 @@
$i18n.get('datepicker_short_friday'), $i18n.get('datepicker_short_friday'),
$i18n.get('datepicker_short_saturday'), $i18n.get('datepicker_short_saturday'),
]" ]"
:month-names="[
$i18n.get('datepicker_month_january'),
$i18n.get('datepicker_month_february'),
$i18n.get('datepicker_month_march'),
$i18n.get('datepicker_month_april'),
$i18n.get('datepicker_month_may'),
$i18n.get('datepicker_month_june'),
$i18n.get('datepicker_month_july'),
$i18n.get('datepicker_month_august'),
$i18n.get('datepicker_month_september'),
$i18n.get('datepicker_month_october'),
$i18n.get('datepicker_month_november'),
$i18n.get('datepicker_month_december')
]"
@update:model-value="validadeValues()" @update:model-value="validadeValues()"
@focus="isTouched = true" /> @focus="isTouched = true" />
</div> </div>

View File

@ -0,0 +1,82 @@
<template>
<div>
<b-field :addons="false">
<label class="label is-inline">
{{ $i18n.getHelperTitle('tainacan-filter-date', 'comparators') }}<span>&nbsp;*&nbsp;</span>
<help-button
:title="$i18n.getHelperTitle('tainacan-filter-date', 'comparators')"
:message="$i18n.getHelperMessage('tainacan-filter-date', 'comparators')" />
</label>
<div>
<b-checkbox
v-for="(comparatorObject, comparatorKey) in comparatorsObject"
:key="comparatorKey"
v-model="comparators"
:native-value="comparatorKey"
:disabled="comparators.indexOf(comparatorKey) >= 0 && comparators.length <= 1"
name="date_filter_options[comparators]"
@update:model-value="emitValues()">
<span v-html="comparatorObject.symbol + '&nbsp;' + comparatorObject.label" />
</b-checkbox>
</div>
</b-field>
</div>
</template>
<script>
export default {
props: {
modelValue: Object
},
emits: [
'update:model-value',
],
data() {
return {
comparatorsObject: Object,
comparators: Array
}
},
created() {
this.comparators = ( this.modelValue && this.modelValue.comparators ) ? this.modelValue.comparators : [ '=', '!=', '>', '>=', '<', '<=' ];
this.comparatorsObject = {
'=': {
symbol: '&#61;',
label: this.$i18n.get('is_equal_to'),
enabled: this.comparators.indexOf('=') < 0 ? 'no' : 'yes'
},
'!=': {
symbol: '&#8800;',
label: this.$i18n.get('is_not_equal_to'),
enabled: this.comparators.indexOf('!=') < 0 ? 'no' : 'yes'
},
'>': {
symbol: '&#62;',
label: this.$i18n.get('greater_than'),
enabled: this.comparators.indexOf('>') < 0 ? 'no' : 'yes'
},
'>=': {
symbol: '&#8805;',
label: this.$i18n.get('greater_than_or_equal_to'),
enabled: this.comparators.indexOf('>=') < 0 ? 'no' : 'yes'
},
'<': {
symbol: '&#60;',
label: this.$i18n.get('less_than'),
enabled: this.comparators.indexOf('<') < 0 ? 'no' : 'yes'
},
'<=': {
symbol: '&#8804;',
label: this.$i18n.get('less_than_or_equal_to'),
enabled: this.comparators.indexOf('<=') < 0 ? 'no' : 'yes'
}
};
},
methods: {
emitValues() {
this.$emit('update:model-value', { comparators: this.comparators });
}
}
}
</script>

View File

@ -1,6 +1,7 @@
<template> <template>
<div class="date-filter-container"> <div class="date-filter-container">
<b-dropdown <b-dropdown
v-if="filterTypeOptions.comparators.length > 1"
:mobile-modal="true" :mobile-modal="true"
aria-role="list" aria-role="list"
trap-focus trap-focus
@ -10,61 +11,30 @@
:aria-label="$i18n.get('label_comparator')" :aria-label="$i18n.get('label_comparator')"
class="button is-white"> class="button is-white">
<span class="icon is-small"> <span class="icon is-small">
<i v-html="comparatorSymbol" /> <i v-html="comparatorsObject[comparator].symbol" />
</span> </span>
<span class="icon"> <span class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-arrowdown" /> <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-arrowdown" />
</span> </span>
</button> </button>
</template> </template>
<template
v-for="(comparatorObject, comparatorKey) in comparatorsObject"
:key="comparatorKey">
<b-dropdown-item <b-dropdown-item
v-if="comparatorObject.enabled == 'yes'"
role="button" role="button"
:class="{ 'is-active': comparator == '=' }" :class="{ 'is-active': comparator == comparatorKey }"
:value="'='" :value="comparatorKey"
aria-role="listitem"> aria-role="listitem"
&#61;&nbsp; {{ $i18n.get('is_equal_to') }} v-html="comparatorObject.symbol + '&nbsp;' + comparatorObject.label" />
</b-dropdown-item> </template>
<b-dropdown-item
role="button"
:class="{ 'is-active': comparator == '!=' }"
:value="'!='"
aria-role="listitem">
&#8800;&nbsp; {{ $i18n.get('is_not_equal_to') }}
</b-dropdown-item>
<b-dropdown-item
role="button"
:class="{ 'is-active': comparator == '>' }"
:value="'>'"
aria-role="listitem">
&#62;&nbsp; {{ $i18n.get('after') }}
</b-dropdown-item>
<b-dropdown-item
role="button"
:class="{ 'is-active': comparator == '>=' }"
:value="'>='"
aria-role="listitem">
&#8805;&nbsp; {{ $i18n.get('after_or_on_day') }}
</b-dropdown-item>
<b-dropdown-item
role="button"
:class="{ 'is-active': comparator == '<' }"
:value="'<'"
aria-role="listitem">
&#60;&nbsp; {{ $i18n.get('before') }}
</b-dropdown-item>
<b-dropdown-item
role="button"
:class="{ 'is-active': comparator == '<=' }"
:value="'<='"
aria-role="listitem">
&#8804;&nbsp; {{ $i18n.get('before_or_on_day') }}
</b-dropdown-item>
</b-dropdown> </b-dropdown>
<b-datepicker <b-datepicker
v-model="value" v-model="value"
position="is-bottom-right" position="is-bottom-right"
:aria-labelledby="'filter-label-id-' + filter.id" :aria-labelledby="'filter-label-id-' + filter.id"
:placeholder="$i18n.get('instruction_select_a_date')" :placeholder="filter.placeholder ? filter.placeholder : $i18n.get('instruction_select_a_date')"
editable editable
:trap-focus="false" :trap-focus="false"
:date-formatter="(date) => dateFormatter(date)" :date-formatter="(date) => dateFormatter(date)"
@ -114,23 +84,13 @@
data() { data() {
return { return {
value: null, value: null,
comparatorsObject: [],
comparator: '=', // =, !=, >, >=, <, <= comparator: '=', // =, !=, >, >=, <, <=
} }
}, },
computed: { computed: {
yearsOnlyValue() { yearsOnlyValue() {
return this.value && typeof this.value.getUTCFullYear === 'function' ? this.value.getUTCFullYear() : null return this.value && typeof this.value.getUTCFullYear === 'function' ? this.value.getUTCFullYear() : null
},
comparatorSymbol() {
switch(this.comparator) {
case '=': return '&#61;';
case '!=': return '&#8800;';
case '>': return '&#62;';
case '>=': return '&#8805;';
case '<': return '&#60;';
case '<=': return '&#8804;';
default: return '';
}
} }
}, },
watch: { watch: {
@ -141,6 +101,41 @@
deep: true, deep: true,
}, },
}, },
created() {
this.comparatorsObject = {
'=': {
symbol: '&#61;',
label: this.$i18n.get('is_equal_to'),
enabled: this.filterTypeOptions.comparators.indexOf('=') < 0 ? 'no' : 'yes'
},
'!=': {
symbol: '&#8800;',
label: this.$i18n.get('is_not_equal_to'),
enabled: this.filterTypeOptions.comparators.indexOf('!=') < 0 ? 'no' : 'yes'
},
'>': {
symbol: '&#62;',
label: this.$i18n.get('after'),
enabled: this.filterTypeOptions.comparators.indexOf('>') < 0 ? 'no' : 'yes'
},
'>=': {
symbol: '&#8805;',
label: this.$i18n.get('after_or_on_day'),
enabled: this.filterTypeOptions.comparators.indexOf('>=') < 0 ? 'no' : 'yes'
},
'<': {
symbol: '&#60;',
label: this.$i18n.get('before'),
enabled: this.filterTypeOptions.comparators.indexOf('<') < 0 ? 'no' : 'yes'
},
'<=': {
symbol: '&#8804;',
label: this.$i18n.get('before_or_on_day'),
enabled: this.filterTypeOptions.comparators.indexOf('<=') < 0 ? 'no' : 'yes'
},
};
this.comparator = this.filterTypeOptions.comparators[0];
},
mounted() { mounted() {
this.updateSelectedValues(); this.updateSelectedValues();
}, },
@ -220,11 +215,19 @@
.date-filter-container { .date-filter-container {
display: flex; display: flex;
height: auto; height: auto;
align-items: stretch;
@supports not (contain: inline-size) {
@media screen and (min-width: 769px) and (max-width: 1500px) { @media screen and (min-width: 769px) and (max-width: 1500px) {
flex-wrap: wrap; flex-wrap: wrap;
height: 60px; height: 60px;
} }
}
@container filterscomponentslist (max-width: 170px) {
flex-wrap: wrap;
height: 60px;
}
.dropdown { .dropdown {
width: auto; width: auto;

View File

@ -13,7 +13,11 @@ class Date extends Filter_Type {
$this->set_name( __('Date', 'tainacan') ); $this->set_name( __('Date', 'tainacan') );
$this->set_supported_types(['date']); $this->set_supported_types(['date']);
$this->set_component('tainacan-filter-date'); $this->set_component('tainacan-filter-date');
$this->set_form_component('tainacan-filter-form-date');
$this->set_use_max_options(false); $this->set_use_max_options(false);
$this->set_default_options([
'comparators' => [ '=', '!=', '>', '>=', '<', '<=' ]
]);
$this->set_preview_template(' $this->set_preview_template('
<div> <div>
<div> <div>
@ -57,6 +61,40 @@ class Date extends Filter_Type {
'); ');
} }
/**
* @inheritdoc
*/
public function get_form_labels(){
return [
'comparators' => [
'title' => __( 'Enabled comparators', 'tainacan' ),
'description' => __( 'A list of comparators to be available in the filter, such as equal, greater than, smaller than, etc.', '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('comparators') ) )
return [
'comparators' => __('"Comparators" array is required', 'tainacan')
];
if ( count( $this->get_option('comparators') ) < 1 )
return [
'comparators' => __('At least one comparator should be provided', 'tainacan')
];
return true;
}
} }
class Date_Helper { class Date_Helper {

View File

@ -0,0 +1,318 @@
<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">&nbsp;*&nbsp;</span>
<span style="font-size: 1.35em;">
<help-button
:title="$i18n.getHelperTitle('tainacan-filter-dates-intersection', 'secondary_filter_metadatum_id')"
:message="$i18n.getHelperMessage('tainacan-filter-dates-intersection', 'secondary_filter_metadatum_id')" />
</span>
</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.metadatum_id )"
:key="option.id"
:value="option.id">
{{ option.name }}
</option>
</b-select>
</b-field>
<fieldset
v-if="secondDateMetadatumId"
class="intersection-explainer-section">
<legend>
<p>
<strong>{{ $i18n.get('info_intersection_explainer') }}</strong>
<span style="font-size: 1.35em;">
<help-button
:title="$i18n.get('label_comparators')"
:message="$i18n.get('info_intersection_rules')" />
</span>
</p>
</legend>
<b-field :addons="false">
<b-select
v-if="showEditFirstComparatorOptions"
v-model="firstComparator"
@update:model-value="emitValues()">
<option
v-for="(comparatorObject, comparatorKey) in comparatorsObject"
:key="comparatorKey"
:value="comparatorKey"
v-html="comparatorObject.symbol + '&nbsp;' + comparatorObject.label" />
</b-select>
<strong
v-else
v-html="comparatorsObject[firstComparator].symbol" />
<p v-if="filter.metadatum">
&nbsp;
<em>{{ filter.metadatum.metadatum_name }}</em>
</p>
<button
v-if="!showEditFirstComparatorOptions"
class="button is-white is-pulled-right"
@click.prevent="showEditFirstComparatorOptions = true">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-edit has-text-secondary" />
</span>
</button>
<button
v-else
class="button is-white is-pulled-right"
@click.prevent="showEditFirstComparatorOptions = false">
<span
v-tooltip="{
content: $i18n.get('close'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-approved has-text-secondary" />
</span>
</button>
</b-field>
<div class="logic-divider">
<span>{{ $i18n.get('label_and') }}</span>
</div>
<b-field :addons="false">
<b-select
v-if="showEditSecondComparatorOptions"
v-model="secondComparator"
@update:model-value="emitValues()">
<option
v-for="(comparatorObject, comparatorKey) in comparatorsObject"
:key="comparatorKey"
:value="comparatorKey"
v-html="comparatorObject.symbol + '&nbsp;' + comparatorObject.label" />
</b-select>
<strong
v-else
v-html="comparatorsObject[secondComparator].symbol" />
<p>&nbsp;<em>{{ secondDateMetadatumName }}</em></p>
<button
v-if="!showEditSecondComparatorOptions"
class="button is-white is-pulled-right"
@click.prevent="showEditSecondComparatorOptions = true">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-edit has-text-secondary" />
</span>
</button>
<button
v-else
class="button is-white is-pulled-right"
@click.prevent="showEditSecondComparatorOptions = false">
<span
v-tooltip="{
content: $i18n.get('close'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-approved has-text-secondary" />
</span>
</button>
</b-field>
</fieldset>
<!-- Much more complicated logic, will be possible if we implement #889 -->
<!-- <b-field
:addons="false"
:label="$i18n.getHelperTitle('tainacan-filter-dates-intersection', 'accept_date_interval')"
style="margin-top: 1.125rem;"
:type="errors && errors['accept_date_interval'] != undefined ? 'is-danger' : ''"
:message="errors && errors['accept_date_interval'] != undefined ? errors['accept_date_interval'] : ''">
&nbsp;
<b-switch
v-model="acceptDateInterval"
size="is-small"
:true-value="'yes'"
:false-value="'no'"
:native-value="acceptDateInterval == 'yes' ? 'yes' : 'no'"
name="accept_date_interval"
@update:model-value="emitValues()">
<help-button
:title="$i18n.getHelperTitle('tainacan-filter-dates-intersection', 'accept_date_interval')"
:message="$i18n.getHelperMessage('tainacan-filter-dates-intersection', 'accept_date_interval')" />
</b-switch>
</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],
secondDateMetadatumName: String,
firstComparator: String,
secondComparator: String,
comparatorsObject: {},
acceptDateInterval: String,
showEditFirstComparatorOptions: false,
showEditSecondComparatorOptions: false
}
},
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.secondDateMetadatumName = this.modelValue && this.modelValue.secondary_filter_metadatum_name ? this.modelValue.secondary_filter_metadatum_name : '';
this.firstComparator = this.modelValue && this.modelValue.first_comparator ? this.modelValue.first_comparator : '>=';
this.secondComparator = this.modelValue && this.modelValue.second_comparator ? this.modelValue.second_comparator : '<=';
this.acceptDateInterval = this.modelValue && this.modelValue.accept_date_interval ? this.modelValue.accept_date_interval : 'no';
this.loading = true;
this.fetchMetadata();
this.comparatorsObject = {
'=': {
symbol: '&#61;',
label: this.$i18n.get('is_equal_to')
},
'!=': {
symbol: '&#8800;',
label: this.$i18n.get('is_not_equal_to')
},
'>': {
symbol: '&#62;',
label: this.$i18n.get('after')
},
'>=': {
symbol: '&#8805;',
label: this.$i18n.get('after_or_on_day')
},
'<': {
symbol: '&#60;',
label: this.$i18n.get('before')
},
'<=': {
symbol: '&#8804;',
label: this.$i18n.get('before_or_on_day')
}
};
},
methods: {
async fetchMetadata() {
let endpoint = this.filter.collection_id && this.filter.collection_id !== 'default' ? ( '/collection/' + this.filter.collection_id + '/metadata' ) : '/metadata';
endpoint += '?metaquery[0][key]=metadata_type&metaquery[0][value]=Tainacan\\Metadata_Types\\Date&nopaging=1&exclude=' + this.filter.metadatum_id;
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 );
this.secondDateMetadatumName = selectedMetadatum ? selectedMetadatum.name : '';
this.secondDateMetadatumId = selectedMetadatum ? selectedMetadatum.id : '';
this.emitValues();
},
emitValues() {
this.$emit('update:model-value', {
first_comparator: this.firstComparator,
second_comparator: this.secondComparator,
secondary_filter_metadatum_id: this.secondDateMetadatumId,
secondary_filter_metadatum_name: this.secondDateMetadatumName,
accept_date_interval: this.acceptDateInterval
});
},
setErrorsAttributes( type, message ) {
this.metadataType = type;
this.metadataMessage = message;
},
clear(){
this.metadataType = '';
this.metadataMessage = '';
},
}
}
</script>
<style lang="scss" scoped>
.intersection-explainer-section {
margin-top: 1.25rem;
padding: 0.75em 0.75em 0.25em 0.75em;
border: 1px solid var(--tainacan-gray1);
legend {
margin: -0.75em 0 0em 0;
background-color: var(--tainacan-background-color);
padding: 5px 5px 5px 0px;
}
.field {
display: flex;
gap: 0.5em;
margin: 0 -0.5em 0.5em 0em;
align-items: center;
strong {
margin-left: 0.75em;
}
}
button {
border-radius: 100em !important;
margin-left: auto;
}
.logic-divider {
display: none;
}
}
</style>

View File

@ -0,0 +1,232 @@
<template>
<div>
<b-datepicker
v-model="dateInit"
:aria-labelledby="'filter-label-id-' + filter.id"
:placeholder="filter.placeholder ? filter.placeholder : $i18n.get('instruction_select_a_date')"
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'),
]"
:month-names="[
$i18n.get('datepicker_month_january'),
$i18n.get('datepicker_month_february'),
$i18n.get('datepicker_month_march'),
$i18n.get('datepicker_month_april'),
$i18n.get('datepicker_month_may'),
$i18n.get('datepicker_month_june'),
$i18n.get('datepicker_month_july'),
$i18n.get('datepicker_month_august'),
$i18n.get('datepicker_month_september'),
$i18n.get('datepicker_month_october'),
$i18n.get('datepicker_month_november'),
$i18n.get('datepicker_month_december')
]"
@focus="isTouched = true"
@update:model-value="($event) => { resetPage(); validadeValues($event) }" />
<p
v-if="filterTypeOptions.accept_date_interval === 'yes'"
style="font-size: 0.75em; margin-bottom: 0.125em;"
class="has-text-centered is-marginless">
{{ $i18n.get('label_until') }}
</p>
<b-datepicker
v-if="filterTypeOptions.accept_date_interval === 'yes'"
v-model="dateEnd"
:aria-labelledby="'filter-label-id-' + filter.id"
:placeholder="filter.placeholder ? filter.placeholder : $i18n.get('instruction_select_a_date')"
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'),
]"
:month-names="[
$i18n.get('datepicker_month_january'),
$i18n.get('datepicker_month_february'),
$i18n.get('datepicker_month_march'),
$i18n.get('datepicker_month_april'),
$i18n.get('datepicker_month_may'),
$i18n.get('datepicker_month_june'),
$i18n.get('datepicker_month_july'),
$i18n.get('datepicker_month_august'),
$i18n.get('datepicker_month_september'),
$i18n.get('datepicker_month_october'),
$i18n.get('datepicker_month_november'),
$i18n.get('datepicker_month_december')
]"
@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.filterTypeOptions.accept_date_interval === 'yes' && 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 ) {
if ( Array.isArray(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 {
const dateValueInit = new Date(metadata.value.replace(/-/g, '/'));
this.dateInit = moment(dateValueInit, 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);
if ( this.dateEnd !== null ) {
let dateEnd = this.dateEnd.getUTCFullYear() + '-' +
('00' + (this.dateEnd.getUTCMonth() + 1)).slice(-2) + '-' +
('00' + this.dateEnd.getUTCDate()).slice(-2);
values = [ dateInit, dateEnd ];
} else {
values = [ dateInit ];
}
}
if ( this.filterTypeOptions.accept_date_interval !== 'yes' ) {
this.$emit('input', {
filter: 'intersection',
type: 'DATE',
compare: this.filterTypeOptions.first_comparator,
metadatum_id: this.metadatumId,
collection_id: this.collectionId,
value: values[0]
});
this.$emit('input', {
filter: 'intersection',
type: 'DATE',
compare: this.filterTypeOptions.second_comparator,
metadatum_id: this.filterTypeOptions.secondary_filter_metadatum_id,
collection_id: this.collectionId,
value: values[0],
secondary: true
});
} else {
// Much more complicated logic to be implemented in the future. See #889
}
}
}
}
</script>
<style scoped>
.field {
margin-bottom: 0.125em !important;
}
.dropdown-trigger input {
font-size: 0.75em;
}
</style>

View File

@ -0,0 +1,137 @@
<?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' => '',
'first_comparator' => '>=',
'second_comparator' => '<=',
'accept_date_interval' => 'no'
]);
$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>
</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' ),
],
'first_comparator' => [
'title' => __( 'First comparator', 'tainacan' ),
'description' => __( 'Comparator to be used for checking the first metadata value.', 'tainacan' ),
],
'second_comparator' => [
'title' => __( 'Second comparator', 'tainacan' ),
'description' => __( 'Comparator to be used for checking the second metadata value.', 'tainacan' ),
],
'accept_date_interval' => [
'title' => __( 'Accept date interval', 'tainacan' ),
'description' => __( 'If checked, the filter will accept date intervals as values.', '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;
$errors = [];
if ( empty($this->get_option('secondary_filter_metadatum_id')) )
$errors['secondary_filter_metadatum_id'] = __('The secondary date metadatum is required.','tainacan');
if ( empty($this->get_option('first_comparator')) )
$errors['first_comparator'] = __('The first comparator is required.','tainacan');
if ( empty($this->get_option('second_comparator')) )
$errors['second_comparator'] = __('The second comparator is required.','tainacan');
if ( empty($this->get_option('accept_date_interval')) )
$errors['accept_date_interval'] = __('The filter should define if it accepts date interval.','tainacan');
return count($errors) > 0 ? $errors : 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']['metadatum'] ) &&
isset( $filter_arguments['filter']['metadatum']['metadatum_name'] )
) {
$filter_arguments['filter']['name'] = $filter_arguments['filter']['metadatum']['metadatum_name'];
}
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();

View File

@ -38,10 +38,12 @@ class Filter_Type_Helper {
$this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Selectbox'); $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\Autocomplete');
$this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Date_Interval'); $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\Numeric_Interval');
$this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\TaxonomyTaginput'); $this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\TaxonomyTaginput');
$this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\TaxonomyCheckbox'); $this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\TaxonomyCheckbox');
$this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Numeric_List_Interval'); $this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Numeric_List_Interval');
$this->Tainacan_Filters->register_filter_type('Tainacan\Filter_Types\Numerics_Intersection');
// the priority should see less than on function // the priority should see less than on function
// `load_admin_page()` of class `Admin` in file /src/views/class-tainacan-admin.php // `load_admin_page()` of class `Admin` in file /src/views/class-tainacan-admin.php

View File

@ -53,8 +53,17 @@ abstract class Filter_Type {
* @var string * @var string
*/ */
private $preview_template = ''; private $preview_template = '';
/**
* Defines if the filter type should use the max options
*/
protected $use_max_options = true; protected $use_max_options = true;
/**
* Defines if the filter type should provide a placeholder for the input field
*/
protected $use_input_placeholder = true;
public function __construct(){ public function __construct(){
add_action('register_filter_types', array(&$this, 'register_filter_type')); add_action('register_filter_types', array(&$this, 'register_filter_type'));
} }
@ -134,6 +143,7 @@ abstract class Filter_Type {
$attributes['supported_types'] = $this->get_supported_types(); $attributes['supported_types'] = $this->get_supported_types();
$attributes['preview_template'] = $this->get_preview_template(); $attributes['preview_template'] = $this->get_preview_template();
$attributes['use_max_options'] = $this->get_use_max_options(); $attributes['use_max_options'] = $this->get_use_max_options();
$attributes['use_input_placeholder'] = $this->get_use_input_placeholder();
$attributes['form_component'] = $this->get_form_component(); $attributes['form_component'] = $this->get_form_component();
return $attributes; return $attributes;
@ -208,6 +218,14 @@ abstract class Filter_Type {
return $this->use_max_options; return $this->use_max_options;
} }
public function set_use_input_placeholder($use_input_placeholder) {
$this->use_input_placeholder = $use_input_placeholder;
}
public function get_use_input_placeholder() {
return $this->use_input_placeholder;
}
/** /**
* Gets one option from the options array. * Gets one option from the options array.
* *

View File

@ -5,6 +5,7 @@
:aria-labelledby="'filter-label-id-' + filter.id" :aria-labelledby="'filter-label-id-' + filter.id"
:aria-minus-label="$i18n.get('label_decrease')" :aria-minus-label="$i18n.get('label_decrease')"
:aria-plus-label="$i18n.get('label_increase')" :aria-plus-label="$i18n.get('label_increase')"
:placeholder="filter.placeholder ? filter.placeholder : ''"
size="is-small" size="is-small"
:step="filterTypeOptions.step" :step="filterTypeOptions.step"
@update:model-value="($event) => { resetPage(); validadeValues($event) }" @update:model-value="($event) => { resetPage(); validadeValues($event) }"
@ -19,6 +20,7 @@
:aria-labelledby="'filter-label-id-' + filter.id" :aria-labelledby="'filter-label-id-' + filter.id"
:aria-minus-label="$i18n.get('label_decrease')" :aria-minus-label="$i18n.get('label_decrease')"
:aria-plus-label="$i18n.get('label_increase')" :aria-plus-label="$i18n.get('label_increase')"
:placeholder="filter.placeholder ? filter.placeholder : ''"
size="is-small" size="is-small"
:step="filterTypeOptions.step" :step="filterTypeOptions.step"
@update:model-value="($event) => { resetPage(); validadeValues($event) }" /> @update:model-value="($event) => { resetPage(); validadeValues($event) }" />

View File

@ -3,7 +3,7 @@
<b-select <b-select
v-model="selectedInterval" v-model="selectedInterval"
expanded expanded
:placeholder="$i18n.get('instruction_select_a_interval')" :placeholder="filter.placeholder ? filter.placeholder : $i18n.get('instruction_select_a_interval')"
@update:model-value="($event) => { resetPage; changeInterval($event) }"> @update:model-value="($event) => { resetPage; changeInterval($event) }">
<option value=""> <option value="">
{{ $i18n.get('label_selectbox_init') }}... {{ $i18n.get('label_selectbox_init') }}...

View File

@ -13,7 +13,7 @@
<b-select <b-select
v-model="step" v-model="step"
name="step_options" name="step_options"
@update:model-value="onUpdateStep"> @update:model-value="emitValues()">
<option value="0.001"> <option value="0.001">
0.001 0.001
</option> </option>
@ -70,7 +70,7 @@
name="max_options" name="max_options"
type="number" type="number"
step="1" step="1"
@update:model-value="onUpdateStep" /> @update:model-value="emitValues()" />
<button <button
class="button is-white is-pulled-right" class="button is-white is-pulled-right"
@click.prevent="showEditStepOptions = false"> @click.prevent="showEditStepOptions = false">
@ -87,6 +87,26 @@
</button> </button>
</div> </div>
</b-field> </b-field>
<b-field :addons="false">
<label class="label is-inline">
{{ $i18n.getHelperTitle('tainacan-filter-numeric', 'comparators') }}<span>&nbsp;*&nbsp;</span>
<help-button
:title="$i18n.getHelperTitle('tainacan-filter-numeric', 'comparators')"
:message="$i18n.getHelperMessage('tainacan-filter-numeric', 'comparators')" />
</label>
<div>
<b-checkbox
v-for="(comparatorObject, comparatorKey) in comparatorsObject"
:key="comparatorKey"
v-model="comparators"
:native-value="comparatorKey"
:disabled="comparators.indexOf(comparatorKey) >= 0 && comparators.length <= 1"
name="numeric_filter_options[comparators]"
@update:model-value="emitValues()">
<span v-html="comparatorObject.symbol + '&nbsp;' + comparatorObject.label" />
</b-checkbox>
</div>
</b-field>
</div> </div>
</template> </template>
@ -102,15 +122,50 @@
data() { data() {
return { return {
step: [Number, String], step: [Number, String],
showEditStepOptions: false showEditStepOptions: false,
comparatorsObject: Object,
comparators: Array
} }
}, },
created() { created() {
this.step = this.modelValue && this.modelValue.step ? this.modelValue.step : 1; this.step = this.modelValue && this.modelValue.step ? this.modelValue.step : 1;
this.comparators = ( this.modelValue && this.modelValue.comparators ) ? this.modelValue.comparators : [ '=', '!=', '>', '>=', '<', '<=' ];
this.comparatorsObject = {
'=': {
symbol: '&#61;',
label: this.$i18n.get('is_equal_to'),
enabled: this.comparators.indexOf('=') < 0 ? 'no' : 'yes'
},
'!=': {
symbol: '&#8800;',
label: this.$i18n.get('is_not_equal_to'),
enabled: this.comparators.indexOf('!=') < 0 ? 'no' : 'yes'
},
'>': {
symbol: '&#62;',
label: this.$i18n.get('after'),
enabled: this.comparators.indexOf('>') < 0 ? 'no' : 'yes'
},
'>=': {
symbol: '&#8805;',
label: this.$i18n.get('after_or_on_day'),
enabled: this.comparators.indexOf('>=') < 0 ? 'no' : 'yes'
},
'<': {
symbol: '&#60;',
label: this.$i18n.get('before'),
enabled: this.comparators.indexOf('<') < 0 ? 'no' : 'yes'
},
'<=': {
symbol: '&#8804;',
label: this.$i18n.get('before_or_on_day'),
enabled: this.comparators.indexOf('<=') < 0 ? 'no' : 'yes'
}
};
}, },
methods: { methods: {
onUpdateStep(modelValue) { emitValues() {
this.$emit('update:model-value', { step: modelValue }); this.$emit('update:model-value', { step: this.step, comparators: this.comparators });
} }
} }
} }

View File

@ -1,6 +1,7 @@
<template> <template>
<div class="numeric-filter-container"> <div class="numeric-filter-container">
<b-dropdown <b-dropdown
v-if="filterTypeOptions.comparators.length > 1"
:mobile-modal="true" :mobile-modal="true"
aria-role="list" aria-role="list"
trap-focus trap-focus
@ -10,62 +11,31 @@
:aria-label="$i18n.get('label_comparator')" :aria-label="$i18n.get('label_comparator')"
class="button is-white"> class="button is-white">
<span class="icon is-small"> <span class="icon is-small">
<i v-html="comparatorSymbol" /> <i v-html="comparatorsObject[comparator].symbol" />
</span> </span>
<span class="icon"> <span class="icon">
<i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-arrowdown" /> <i class="tainacan-icon tainacan-icon-1-25em tainacan-icon-arrowdown" />
</span> </span>
</button> </button>
</template> </template>
<template
v-for="(comparatorObject, comparatorKey) in comparatorsObject"
:key="comparatorKey">
<b-dropdown-item <b-dropdown-item
v-if="comparatorObject.enabled == 'yes'"
role="button" role="button"
:class="{ 'is-active': comparator == '=' }" :class="{ 'is-active': comparator == comparatorKey }"
:value="'='" :value="comparatorKey"
aria-role="listitem"> aria-role="listitem"
&#61;&nbsp; {{ $i18n.get('is_equal_to') }} v-html="comparatorObject.symbol + '&nbsp;' + comparatorObject.label" />
</b-dropdown-item> </template>
<b-dropdown-item
role="button"
:class="{ 'is-active': comparator == '!=' }"
:value="'!='"
aria-role="listitem">
&#8800;&nbsp; {{ $i18n.get('is_not_equal_to') }}
</b-dropdown-item>
<b-dropdown-item
role="button"
:class="{ 'is-active': comparator == '>' }"
:value="'>'"
aria-role="listitem">
&#62;&nbsp; {{ $i18n.get('greater_than') }}
</b-dropdown-item>
<b-dropdown-item
role="button"
:class="{ 'is-active': comparator == '>=' }"
:value="'>='"
aria-role="listitem">
&#8805;&nbsp; {{ $i18n.get('greater_than_or_equal_to') }}
</b-dropdown-item>
<b-dropdown-item
role="button"
:class="{ 'is-active': comparator == '<' }"
:value="'<'"
aria-role="listitem">
&#60;&nbsp; {{ $i18n.get('less_than') }}
</b-dropdown-item>
<b-dropdown-item
role="button"
:class="{ 'is-active': comparator == '<=' }"
:value="'<='"
aria-role="listitem">
&#8804;&nbsp; {{ $i18n.get('less_than_or_equal_to') }}
</b-dropdown-item>
</b-dropdown> </b-dropdown>
<b-numberinput <b-numberinput
v-model="value" v-model="value"
:aria-labelledby="'filter-label-id-' + filter.id" :aria-labelledby="'filter-label-id-' + filter.id"
:aria-minus-label="$i18n.get('label_decrease')" :aria-minus-label="$i18n.get('label_decrease')"
:aria-plus-label="$i18n.get('label_increase')" :aria-plus-label="$i18n.get('label_increase')"
:placeholder="filter.placeholder ? filter.placeholder : ''"
size="is-small" size="is-small"
:step="Number(filterTypeOptions.step)" :step="Number(filterTypeOptions.step)"
@update:model-value="($event) => { resetPage($event); emit($event); }" /> @update:model-value="($event) => { resetPage($event); emit($event); }" />
@ -89,19 +59,6 @@
comparator: '=' // =, !=, >, >=, <, <= comparator: '=' // =, !=, >, >=, <, <=
} }
}, },
computed: {
comparatorSymbol() {
switch(this.comparator) {
case '=': return '&#61;';
case '!=': return '&#8800;';
case '>': return '&#62;';
case '>=': return '&#8805;';
case '<': return '&#60;';
case '<=': return '&#8804;';
default: return '';
}
}
},
watch: { watch: {
'query': { 'query': {
handler() { handler() {
@ -110,6 +67,41 @@
deep: true deep: true
} }
}, },
created() {
this.comparatorsObject = {
'=': {
symbol: '&#61;',
label: this.$i18n.get('is_equal_to'),
enabled: this.filterTypeOptions.comparators.indexOf('=') < 0 ? 'no' : 'yes'
},
'!=': {
symbol: '&#8800;',
label: this.$i18n.get('is_not_equal_to'),
enabled: this.filterTypeOptions.comparators.indexOf('!=') < 0 ? 'no' : 'yes'
},
'>': {
symbol: '&#62;',
label: this.$i18n.get('greater_than'),
enabled: this.filterTypeOptions.comparators.indexOf('>') < 0 ? 'no' : 'yes'
},
'>=': {
symbol: '&#8805;',
label: this.$i18n.get('greater_than_or_equal_to'),
enabled: this.filterTypeOptions.comparators.indexOf('>=') < 0 ? 'no' : 'yes'
},
'<': {
symbol: '&#60;',
label: this.$i18n.get('less_than'),
enabled: this.filterTypeOptions.comparators.indexOf('<') < 0 ? 'no' : 'yes'
},
'<=': {
symbol: '&#8804;',
label: this.$i18n.get('less_than_or_equal_to'),
enabled: this.filterTypeOptions.comparators.indexOf('<=') < 0 ? 'no' : 'yes'
},
};
this.comparator = this.filterTypeOptions.comparators[0];
},
mounted() { mounted() {
this.updateSelectedValues(); this.updateSelectedValues();
}, },
@ -165,15 +157,25 @@
height: auto; height: auto;
align-items: stretch; align-items: stretch;
@supports not (contain: inline-size) {
@media screen and (min-width: 769px) and (max-width: 1500px) { @media screen and (min-width: 769px) and (max-width: 1500px) {
flex-wrap: wrap; flex-wrap: wrap;
align-items: center;
height: 60px; height: 60px;
} }
}
@container filterscomponentslist (max-width: 170px) {
flex-wrap: wrap;
height: 60px;
.dropdown {
flex-grow: 2 !important;
}
}
.dropdown { .dropdown {
width: auto; width: auto;
flex-grow: 2; flex-grow: 0;
.dropdown-trigger button { .dropdown-trigger button {
padding: 2px 0.5em 2px 0.5em !important; padding: 2px 0.5em 2px 0.5em !important;

View File

@ -16,7 +16,8 @@ class Numeric extends Filter_Type {
$this->set_form_component('tainacan-filter-form-numeric'); $this->set_form_component('tainacan-filter-form-numeric');
$this->set_use_max_options(false); $this->set_use_max_options(false);
$this->set_default_options([ $this->set_default_options([
'step' => 1 'step' => 1,
'comparators' => [ '=', '!=', '>', '>=', '<', '<=' ]
]); ]);
$this->set_preview_template(' $this->set_preview_template('
<div> <div>
@ -77,6 +78,10 @@ class Numeric extends Filter_Type {
'step' => [ 'step' => [
'title' => __( 'Step', 'tainacan' ), 'title' => __( 'Step', 'tainacan' ),
'description' => __( 'The amount to be increased or decreased when clicking on the filter control buttons. This also defines whether the input accepts decimal numbers.', 'tainacan' ), 'description' => __( 'The amount to be increased or decreased when clicking on the filter control buttons. This also defines whether the input accepts decimal numbers.', 'tainacan' ),
],
'comparators' => [
'title' => __( 'Enabled comparators', 'tainacan' ),
'description' => __( 'A list of comparators to be available in the filter, such as equal, greater than, smaller than, etc.', 'tainacan' ),
] ]
]; ];
} }
@ -89,13 +94,24 @@ class Numeric extends Filter_Type {
if ( !in_array($filter->get_status(), apply_filters('tainacan-status-require-validation', ['publish','future','private'])) ) if ( !in_array($filter->get_status(), apply_filters('tainacan-status-require-validation', ['publish','future','private'])) )
return true; return true;
if ( empty($this->get_option('step')) ) { $errors = [];
return [
if ( empty($this->get_option('step')) )
$errors[] = [
'step' => __('"Step" value is required','tainacan') 'step' => __('"Step" value is required','tainacan')
]; ];
}
return true; if ( empty($this->get_option('comparators')) )
$errors[] = [
'comparators' => __('"Comparators" array is required', 'tainacan')
];
if ( count( $this->get_option('comparators') ) < 1 )
$errors[] = [
'comparators' => __('At least one comparator should be provided', 'tainacan')
];
return count($errors) ? $errors : true;
} }
} }
@ -134,6 +150,8 @@ class Numeric_Helper {
case '<=': case '<=':
$filter_arguments['label'] = '&#8804; ' . $filter_arguments['label'][0]; $filter_arguments['label'] = '&#8804; ' . $filter_arguments['label'][0];
break; break;
default:
$filter_arguments['label'] = $filter_arguments['label'][0];
} }
} }

View File

@ -0,0 +1,410 @@
<template>
<div>
<b-field :addons="false">
<label class="label is-inline">
{{ $i18n.getHelperTitle('tainacan-filter-numeric-interval', 'step') }}<span>&nbsp;*&nbsp;</span>
<span style="font-size: 1.35em;">
<help-button
:title="$i18n.getHelperTitle('tainacan-filter-numeric-interval', 'step')"
:message="$i18n.getHelperMessage('tainacan-filter-numeric-interval', 'step')" />
</span>
</label>
<div
v-if="!showEditStepOptions"
class="is-flex">
<b-select
v-model="step"
name="step_options"
@update:model-value="emitValues()">
<option value="0.001">
0.001
</option>
<option value="0.01">
0.01
</option>
<option value="0.1">
0.1
</option>
<option value="1">
1
</option>
<option value="2">
2
</option>
<option value="5">
5
</option>
<option value="10">
10
</option>
<option value="100">
100
</option>
<option value="1000">
1000
</option>
<option
v-if="step && ![0.001,0.01,0.1,1,2,5,10,100,1000].find( (element) => element == step )"
:value="step">
{{ step }}</option>
</b-select>
<button
class="button is-white is-pulled-right"
:aria-label="$i18n.get('edit')"
@click.prevent="showEditStepOptions = true">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-edit has-text-secondary" />
</span>
</button>
</div>
<div
v-if="showEditStepOptions"
class="is-flex">
<b-input
v-model="step"
name="max_options"
type="number"
step="1"
@update:model-value="emitValues()" />
<button
class="button is-white is-pulled-right"
@click.prevent="showEditStepOptions = false">
<span
v-tooltip="{
content: $i18n.get('close'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-close has-text-secondary" />
</span>
</button>
</div>
</b-field>
<b-field
:addons="false"
:type="metadataType"
:message="metadataMessage">
<label class="label is-inline">
{{ $i18n.getHelperTitle('tainacan-filter-numerics-intersection', 'secondary_filter_metadatum_id') }}<span :class="metadataType">&nbsp;*&nbsp;</span>
<help-button
:title="$i18n.getHelperTitle('tainacan-filter-numerics-intersection', 'secondary_filter_metadatum_id')"
:message="$i18n.getHelperMessage('tainacan-filter-numerics-intersection', 'secondary_filter_metadatum_id')" />
</label>
<b-select
v-model="secondNumericMetadatumId"
name="numerics_intersect[secondary_filter_metadatum_id]"
:placeholder="$i18n.get('instruction_select_second_numeric_to_compare' )"
:loading="loading"
expanded
@change="onUpdateSecondNumericMetadatumId()"
@focus="clear()">
<option :value="''">
{{ $i18n.get('instruction_select_second_numeric_to_compare' ) }}
</option>
<option
v-for="option in metadata.filter(aMetadatum => aMetadatum.id != filter.metadatum_id )"
:key="option.id"
:value="option.id">
{{ option.name }}
</option>
</b-select>
</b-field>
<fieldset
v-if="secondNumericMetadatumId"
class="intersection-explainer-section">
<legend>
<p>
<strong>{{ $i18n.get('info_intersection_explainer') }}</strong>
<span style="font-size: 1.35em;">
<help-button
:title="$i18n.get('label_comparators')"
:message="$i18n.get('info_intersection_rules')" />
</span>
</p>
</legend>
<b-field :addons="false">
<b-select
v-if="showEditFirstComparatorOptions"
v-model="firstComparator"
@update:model-value="emitValues()">
<option
v-for="(comparatorObject, comparatorKey) in comparatorsObject"
:key="comparatorKey"
:value="comparatorKey"
v-html="comparatorObject.symbol + '&nbsp;' + comparatorObject.label" />
</b-select>
<strong
v-else
v-html="comparatorsObject[firstComparator].symbol" />
<p v-if="filter.metadatum">
&nbsp;
<em>{{ filter.metadatum.metadatum_name }}</em>
</p>
<button
v-if="!showEditFirstComparatorOptions"
class="button is-white is-pulled-right"
@click.prevent="showEditFirstComparatorOptions = true">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-edit has-text-secondary" />
</span>
</button>
<button
v-else
class="button is-white is-pulled-right"
@click.prevent="showEditFirstComparatorOptions = false">
<span
v-tooltip="{
content: $i18n.get('close'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-approved has-text-secondary" />
</span>
</button>
</b-field>
<div class="logic-divider">
<span>{{ $i18n.get('label_and') }}</span>
</div>
<b-field :addons="false">
<b-select
v-if="showEditSecondComparatorOptions"
v-model="secondComparator"
@update:model-value="emitValues()">
<option
v-for="(comparatorObject, comparatorKey) in comparatorsObject"
:key="comparatorKey"
:value="comparatorKey"
v-html="comparatorObject.symbol + '&nbsp;' + comparatorObject.label" />
</b-select>
<strong
v-else
v-html="comparatorsObject[secondComparator].symbol" />
<p>&nbsp;<em>{{ secondNumericMetadatumName }}</em></p>
<button
v-if="!showEditSecondComparatorOptions"
class="button is-white is-pulled-right"
@click.prevent="showEditSecondComparatorOptions = true">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-edit has-text-secondary" />
</span>
</button>
<button
v-else
class="button is-white is-pulled-right"
@click.prevent="showEditSecondComparatorOptions = false">
<span
v-tooltip="{
content: $i18n.get('close'),
autoHide: true,
placement: 'bottom',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon">
<i class="tainacan-icon tainacan-icon-18px tainacan-icon-approved has-text-secondary" />
</span>
</button>
</b-field>
</fieldset>
<!-- Much more complicated logic, will be possible if we implement #889 -->
<!-- <b-field
:addons="false"
:label="$i18n.getHelperTitle('tainacan-filter-numerics-intersection', 'accept_numeric_interval')"
style="margin-top: 1.125rem;"
:type="errors && errors['accept_numeric_interval'] != undefined ? 'is-danger' : ''"
:message="errors && errors['accept_numeric_interval'] != undefined ? errors['accept_numeric_interval'] : ''">
&nbsp;
<b-switch
v-model="acceptNumericInterval"
size="is-small"
:true-value="'yes'"
:false-value="'no'"
:native-value="acceptNumericInterval == 'yes' ? 'yes' : 'no'"
name="accept_numeric_interval"
@update:model-value="emitValues()">
<help-button
:title="$i18n.getHelperTitle('tainacan-filter-numerics-intersection', 'accept_numeric_interval')"
:message="$i18n.getHelperMessage('tainacan-filter-numerics-intersection', 'accept_numeric_interval')" />
</b-switch>
</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 {
step: [Number, String],
showEditStepOptions: false,
metadata: [],
loading: true,
metadataType: '',
metadataMessage: '',
secondNumericMetadatumId: [Number, String],
secondNumericMetadatumName: String,
firstComparator: String,
secondComparator: String,
comparatorsObject: {},
acceptNumericInterval: String,
showEditFirstComparatorOptions: false,
showEditSecondComparatorOptions: false
}
},
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.step = this.modelValue && this.modelValue.step ? this.modelValue.step : 1;
this.secondNumericMetadatumId = this.modelValue && this.modelValue.secondary_filter_metadatum_id ? this.modelValue.secondary_filter_metadatum_id : '';
this.secondNumericMetadatumName = this.modelValue && this.modelValue.secondary_filter_metadatum_name ? this.modelValue.secondary_filter_metadatum_name : '';
this.firstComparator = this.modelValue && this.modelValue.first_comparator ? this.modelValue.first_comparator : '>=';
this.secondComparator = this.modelValue && this.modelValue.second_comparator ? this.modelValue.second_comparator : '<=';
this.acceptNumericInterval = this.modelValue && this.modelValue.accept_numeric_interval ? this.modelValue.accept_numeric_interval : 'no';
this.loading = true;
this.fetchMetadata();
this.comparatorsObject = {
'=': {
symbol: '&#61;',
label: this.$i18n.get('is_equal_to')
},
'!=': {
symbol: '&#8800;',
label: this.$i18n.get('is_not_equal_to')
},
'>': {
symbol: '&#62;',
label: this.$i18n.get('greater_than')
},
'>=': {
symbol: '&#8805;',
label: this.$i18n.get('greater_than_or_equal_to')
},
'<': {
symbol: '&#60;',
label: this.$i18n.get('less_than')
},
'<=': {
symbol: '&#8804;',
label: this.$i18n.get('less_than_or_equal_to')
}
};
},
methods: {
async fetchMetadata() {
let endpoint = this.filter.collection_id && this.filter.collection_id !== 'default' ? ( '/collection/' + this.filter.collection_id + '/metadata' ) : '/metadata';
endpoint += '?metaquery[0][key]=metadata_type&metaquery[0][value]=Tainacan\\Metadata_Types\\Numeric&nopaging=1&exclude=' + this.filter.metadatum_id;
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);
});
},
onUpdateSecondNumericMetadatumId() {
const selectedMetadatum = this.metadata.find( aMetadatum => aMetadatum.id == this.secondNumericMetadatumId );
this.secondNumericMetadatumName = selectedMetadatum ? selectedMetadatum.name : '';
this.secondNumericMetadatumId = selectedMetadatum ? selectedMetadatum.id : '';
this.emitValues();
},
emitValues() {
this.$emit('update:model-value', {
step: this.step,
first_comparator: this.firstComparator,
second_comparator: this.secondComparator,
secondary_filter_metadatum_id: this.secondNumericMetadatumId,
secondary_filter_metadatum_name: this.secondNumericMetadatumName,
accept_numeric_interval: this.acceptNumericInterval
});
},
setErrorsAttributes( type, message ) {
this.metadataType = type;
this.metadataMessage = message;
},
clear(){
this.metadataType = '';
this.metadataMessage = '';
},
}
}
</script>
<style lang="scss" scoped>
.intersection-explainer-section {
margin-top: 1.25rem;
padding: 0.75em 0.75em 0.25em 0.75em;
border: 1px solid var(--tainacan-gray1);
legend {
margin: -0.75em 0 0em 0;
background-color: var(--tainacan-background-color);
padding: 5px 5px 5px 0px;
}
.field {
display: flex;
gap: 0.5em;
margin: 0 -0.5em 0.5em 0em;
align-items: center;
strong {
margin-left: 0.75em;
}
}
button {
border-radius: 100em !important;
margin-left: auto;
}
.logic-divider {
display: none;
}
}
</style>

View File

@ -0,0 +1,150 @@
<template>
<div>
<b-numberinput
v-model="valueInit"
:aria-labelledby="'filter-label-id-' + filter.id"
:aria-minus-label="$i18n.get('label_decrease')"
:aria-plus-label="$i18n.get('label_increase')"
:placeholder="filter.placeholder ? filter.placeholder : ''"
size="is-small"
:step="filterTypeOptions.step"
@update:model-value="($event) => { resetPage(); validadeValues($event) }"
/>
<p
v-if="filterTypeOptions.accept_numeric_interval === 'yes'"
style="font-size: 0.75em; margin-bottom: 0.125em;"
class="has-text-centered is-marginless">
{{ $i18n.get('label_until') }}
</p>
<b-numberinput
v-if="filterTypeOptions.accept_numeric_interval === 'yes'"
v-model="valueEnd"
:aria-labelledby="'filter-label-id-' + filter.id"
:aria-minus-label="$i18n.get('label_decrease')"
:aria-plus-label="$i18n.get('label_increase')"
:placeholder="filter.placeholder ? filter.placeholder : ''"
size="is-small"
:step="filterTypeOptions.step"
@update:model-value="($event) => { resetPage(); validadeValues($event) }" />
</div>
</template>
<script>
import { filterTypeMixin } from '../../../js/filter-types-mixin';
export default {
mixins: [ filterTypeMixin ],
emits: [
'input',
],
data(){
return {
valueInit: null,
valueEnd: null
}
},
watch: {
'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.filterTypeOptions.accept_numeric_interval !== 'yes' )
this.valueEnd = this.valueInit;
if (this.valueInit == null || this.valueEnd == null )
return
if (this.valueInit.constructor == Number)
this.valueInit = this.valueInit.valueOf();
if (this.valueEnd.constructor == Number)
this.valueEnd = this.valueEnd.valueOf();
this.valueInit = parseFloat(this.valueInit);
this.valueEnd = parseFloat(this.valueEnd);
if ( isNaN(this.valueInit) || isNaN(this.valueEnd) )
return
if ( this.filterTypeOptions.accept_numeric_interval === 'yes' && this.valueInit > this.valueEnd ) {
this.showErrorMessage();
return;
}
this.emit();
}, 600),
// message for error
showErrorMessage(){
this.$buefy.toast.open({
duration: 3000,
message: this.$i18n.get('info_error_first_value_greater'),
position: 'is-bottom',
type: 'is-danger'
})
},
// emit the operation for listeners
emit() {
let values = [ this.valueInit, this.valueEnd ];
let type = ! Number.isInteger( this.valueInit ) || ! Number.isInteger( this.valueEnd ) ? 'DECIMAL(20,3)' : 'NUMERIC';
if ( this.filterTypeOptions.accept_numeric_interval !== 'yes' ) {
this.$emit('input', {
filter: 'intersection',
type: type,
compare: this.filterTypeOptions.first_comparator,
metadatum_id: this.metadatumId,
collection_id: this.collectionId,
value: values[0]
});
this.$emit('input', {
filter: 'intersection',
type: type,
compare: this.filterTypeOptions.second_comparator,
metadatum_id: this.filterTypeOptions.secondary_filter_metadatum_id,
collection_id: this.collectionId,
value: values[0],
secondary: true
});
} else {
// Much more complicated logic to be implemented in the future. See #889
}
},
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 metaquery = this.query.metaquery[ index ];
if ( metaquery.value ) {
if ( Array.isArray(metaquery.value) && metaquery.value.length > 1 ) {
this.valueInit = new Number(metaquery.value[0]);
this.valueEnd = new Number(metaquery.value[1]);
} else {
this.valueInit = new Number(metaquery.value);
}
}
} else {
this.valueInit = null;
this.valueEnd = null;
}
},
}
}
</script>
<style scoped>
.field {
margin-bottom: 0.125em !important;
}
</style>

View File

@ -0,0 +1,148 @@
<?php
namespace Tainacan\Filter_Types;
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );
/**
* Class TainacanFilterType
*/
class Numerics_Intersection extends Filter_Type {
function __construct(){
$this->set_name( __('Numerics Intersection', 'tainacan') );
$this->set_supported_types(['float']);
$this->set_component('tainacan-filter-numerics-intersection');
$this->set_form_component('tainacan-filter-form-numerics-intersection');
$this->set_default_options([
'step' => 1,
'secondary_filter_metadatum_id' => '',
'secondary_filter_metadatum_name' => '',
'first_comparator' => '>=',
'second_comparator' => '<=',
'accept_numeric_interval' => 'no'
]);
$this->set_use_max_options(false);
$this->set_preview_template('
<div>
<div class="b-numberinput field is-grouped">
<p class="control">
<button type="button" class="button is-primary is-small">
<span class="icon is-small">
<i class="mdi mdi-minus"></i>
</span>
</button>
</p>
<div class="control is-small is-clearfix">
<input type="number" step="0.01" class="input is-small" value="6">
</div>
<p class="control">
<button type="button" class="button is-primary is-small">
<span class="icon is-small">
<i class="mdi mdi-plus"></i>
</span>
</button>
</p>
</div>
</div>
');
}
public function get_form_labels(){
return [
'step' => [
'title' => __( 'Step', 'tainacan' ),
'description' => __( 'The amount to be increased or decreased when clicking on the filter control buttons. This also defines whether the input accepts decimal numbers.', 'tainacan' ),
],
'secondary_filter_metadatum_id' => [
'title' => __( 'Second numeric metadatum', 'tainacan' ),
'description' => __( 'The other metadatum to which this filter will compare values to find if there is an intersection of numeric values.', 'tainacan' ),
],
'secondary_filter_metadatum_name' => [
'title' => __( 'Second numeric metadatum', 'tainacan' ),
'description' => __( 'Label of the other metadatum to which this filter will compare values to find if there is an intersection of numeric values.', 'tainacan' ),
],
'first_comparator' => [
'title' => __( 'First comparator', 'tainacan' ),
'description' => __( 'Comparator to be used for checking the first metadata value.', 'tainacan' ),
],
'second_comparator' => [
'title' => __( 'Second comparator', 'tainacan' ),
'description' => __( 'Comparator to be used for checking the second metadata value.', 'tainacan' ),
],
'accept_numeric_interval' => [
'title' => __( 'Accept numeric interval', 'tainacan' ),
'description' => __( 'If checked, the filter will accept numeric intervals as values.', '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;
$errors = [];
if ( empty($this->get_option('secondary_filter_metadatum_id')) )
$errors['secondary_filter_metadatum_id'] = __('The secondary numeric metadatum is required.','tainacan');
if ( empty($this->get_option('first_comparator')) )
$errors['first_comparator'] = __('The first comparator is required.','tainacan');
if ( empty($this->get_option('second_comparator')) )
$errors['second_comparator'] = __('The second comparator is required.','tainacan');
if ( empty($this->get_option('accept_numeric_interval')) )
$errors['accept_numeric_interval'] = __('The filter should define if it accepts a numeric interval.','tainacan');
return count($errors) > 0 ? $errors : true;
}
}
class Numerics_Intersection_Interval_Helper {
use \Tainacan\Traits\Singleton_Instance;
protected function init() {
add_filter( 'tainacan-api-items-tainacan-filter-numerics-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']['metadatum'] ) &&
isset( $filter_arguments['filter']['metadatum']['metadatum_name'] )
) {
$filter_arguments['filter']['name'] = $filter_arguments['filter']['metadatum']['metadatum_name'];
}
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;
}
}
Numerics_Intersection_Interval_Helper::get_instance();

View File

@ -6,7 +6,7 @@
v-if="!isLoadingOptions" v-if="!isLoadingOptions"
:model-value="selected" :model-value="selected"
:aria-labelledby="'filter-label-id-' + filter.id" :aria-labelledby="'filter-label-id-' + filter.id"
:placeholder="$i18n.get('label_selectbox_init')" :placeholder="filter.placeholder ? filter.placeholder : $i18n.get('label_selectbox_init')"
expanded expanded
@update:model-value="($event) => { resetPage(); onSelect($event) }"> @update:model-value="($event) => { resetPage(); onSelect($event) }">
<option value=""> <option value="">

View File

@ -13,7 +13,7 @@
attached attached
:aria-close-label="$i18n.get('remove_value')" :aria-close-label="$i18n.get('remove_value')"
:aria-labelledby="'filter-label-id-' + filter.id" :aria-labelledby="'filter-label-id-' + filter.id"
:placeholder="getInputPlaceholder" :placeholder="filter.placeholder ? filter.placeholder : getInputPlaceholder"
check-infinite-scroll check-infinite-scroll
@update:model-value="($event) => { resetPage(); onSelect($event) }" @update:model-value="($event) => { resetPage(); onSelect($event) }"
@typing="search" @typing="search"

View File

@ -6,24 +6,13 @@
@touchstart="setFilterFocus(filter.id)" @touchstart="setFilterFocus(filter.id)"
@mousedown="setFilterFocus(filter.id)"> @mousedown="setFilterFocus(filter.id)">
<b-collapse <b-collapse
v-if="displayFilter" v-if="!hideCollapses && displayFilter"
v-model="singleCollapseOpen" v-model="singleCollapseOpen"
class="show" class="show"
animation="filter-item"> animation="filter-item">
<template #trigger="props"> <template #trigger="props">
<button <button
:id="'filter-label-id-' + filter.id" :id="'filter-label-id-' + filter.id"
v-tooltip="{
delay: {
shown: 500,
hide: 300,
},
content: filter.name,
html: false,
autoHide: false,
placement: 'top-start',
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
}"
:for="'filter-input-id-' + filter.id" :for="'filter-input-id-' + filter.id"
:aria-controls="'filter-input-id-' + filter.id" :aria-controls="'filter-input-id-' + filter.id"
:aria-expanded="singleCollapseOpen" :aria-expanded="singleCollapseOpen"
@ -37,10 +26,22 @@
}" }"
class="tainacan-icon tainacan-icon-1-25em" /> class="tainacan-icon tainacan-icon-1-25em" />
</span> </span>
<span class="collapse-label">{{ filter.name }}</span> <span
class="collapse-label">
{{ filter.name }}
</span>
<help-button
v-if="filter.description_bellow_name !== 'yes' && filter.description"
:title="filter.name"
:message="filter.description" />
</button> </button>
</template> </template>
<div :id="'filter-input-id-' + filter.id"> <div :id="'filter-input-id-' + filter.id">
<p
v-if="filter.description_bellow_name === 'yes' && filter.description"
class="filter-description-help-info">
{{ filter.description }}
</p>
<component <component
:is="filter.filter_type_object ? filter.filter_type_object.component : null" :is="filter.filter_type_object ? filter.filter_type_object.component : null"
:filter="filter" :filter="filter"
@ -55,14 +56,21 @@
</div> </div>
</b-collapse> </b-collapse>
<div <div
v-if="beginWithFilterCollapsed && !displayFilter" v-if="!hideCollapses && beginWithFilterCollapsed && !displayFilter"
class="collapse show disabled-filter"> class="collapse show disabled-filter">
<div class="collapse-trigger"> <div class="collapse-trigger">
<button <button
:for="'filter-input-id-' + filter.id"
:aria-controls="'filter-input-id-' + filter.id"
class="label"
@click="displayFilter = true">
<span class="icon">
<i class="tainacan-icon tainacan-icon-arrowright tainacan-icon-1-25em" />
</span>
<span
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('instruction_click_to_load_filter'), content: $i18n.get('instruction_click_to_load_filter'),
@ -71,17 +79,48 @@
placement: 'top-start', placement: 'top-start',
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''] popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
}" }"
:for="'filter-input-id-' + filter.id" class="collapse-label">
:aria-controls="'filter-input-id-' + filter.id" {{ filter.name }}
class="label"
@click="displayFilter = true">
<span class="icon">
<i class="tainacan-icon tainacan-icon-arrowright tainacan-icon-1-25em" />
</span> </span>
<span class="collapse-label">{{ filter.name }}</span> <help-button
v-if="filter.description_bellow_name !== 'yes' && filter.description"
:title="filter.name"
:message="filter.description" />
</button> </button>
</div> </div>
</div> </div>
<template v-if="hideCollapses">
<label
:for="'filter-input-id-' + filter.id"
class="label">
<span
class="collapse-label">
{{ filter.name }}
</span>
<help-button
v-if="filter.description_bellow_name !== 'yes' && filter.description"
:title="filter.name"
:message="filter.description" />
</label>
<div :id="'filter-input-id-' + filter.id">
<p
v-if="filter.description_bellow_name === 'yes' && filter.description"
class="filter-description-help-info">
{{ filter.description }}
</p>
<component
:is="filter.filter_type_object ? filter.filter_type_object.component : null"
:filter="filter"
:query="query"
:is-using-elastic-search="isUsingElasticSearch"
:is-repository-level="isRepositoryLevel"
:is-loading-items="isLoadingItems"
:current-collection-id="$eventBusSearch.collectionId"
:filters-as-modal="filtersAsModal"
@input="onInput"
@update-parent-collapse="onFilterUpdateParentCollapse" />
</div>
</template>
</b-field> </b-field>
</template> </template>
@ -100,8 +139,10 @@
TainacanFilterTaxonomyCheckbox: defineAsyncComponent(() => import('./taxonomy/TainacanFilterCheckbox.vue')), TainacanFilterTaxonomyCheckbox: defineAsyncComponent(() => import('./taxonomy/TainacanFilterCheckbox.vue')),
TainacanFilterTaxonomyTaginput: defineAsyncComponent(() => import('./taxonomy/TainacanFilterTaginput.vue')), TainacanFilterTaxonomyTaginput: defineAsyncComponent(() => import('./taxonomy/TainacanFilterTaginput.vue')),
TainacanFilterDateInterval: defineAsyncComponent(() => import('./date-interval/TainacanFilterDateInterval.vue')), TainacanFilterDateInterval: defineAsyncComponent(() => import('./date-interval/TainacanFilterDateInterval.vue')),
TainacanFilterDatesIntersection: defineAsyncComponent(() => import('./dates-intersection/TainacanFilterDatesIntersection.vue')),
TainacanFilterNumericInterval: defineAsyncComponent(() => import('./numeric-interval/TainacanFilterNumericInterval.vue')), TainacanFilterNumericInterval: defineAsyncComponent(() => import('./numeric-interval/TainacanFilterNumericInterval.vue')),
TainacanFilterNumericListInterval: defineAsyncComponent(() => import('./numeric-list-interval/TainacanFilterNumericListInterval.vue')) TainacanFilterNumericListInterval: defineAsyncComponent(() => import('./numeric-list-interval/TainacanFilterNumericListInterval.vue')),
TainacanFilterNumericsIntersection: defineAsyncComponent(() => import('./numerics-intersection/TainacanFilterNumericsIntersection.vue'))
}, },
props: { props: {
filter: Object, filter: Object,
@ -110,7 +151,8 @@
expandAll: true, expandAll: true,
isLoadingItems: true, isLoadingItems: true,
filtersAsModal: Boolean, filtersAsModal: Boolean,
isMobileScreen: false isMobileScreen: false,
hideCollapses: false
}, },
data() { data() {
return { return {
@ -203,7 +245,29 @@
.column { .column {
padding: 0.75em 1px 0.75em 0 !important; padding: 0.75em 1px 0.75em 0 !important;
} }
& > .label {
display: block !important;
width: 100%;
overflow-x: hidden;
text-overflow: ellipsis;
line-height: 1.4em !important;
border: none;
background-color: transparent;
color: var(--tainacan-label-color);
text-align: left;
outline: none;
padding: 0 !important;
margin: 0 0 8px 0;
.tainacan-help-tooltip-trigger {
font-size: 1.188em;
.icon {
margin-right: 0px;
margin-left: 6px;
}
}
}
.collapse { .collapse {
.label { .label {
display: inline-flex; display: inline-flex;
@ -216,6 +280,15 @@
outline: none; outline: none;
padding: 0 !important; padding: 0 !important;
margin: 0; margin: 0;
.tainacan-help-tooltip-trigger {
font-size: 1.188em;
.icon {
margin-right: 0px;
margin-left: 6px;
}
}
} }
} }
@ -225,6 +298,13 @@
width: 100%; width: 100%;
} }
.filter-description-help-info {
font-size: 0.75em;
color: var(--tainacan-info-color);
margin-top: -0.25em;
margin-bottom: 0.75em;
}
.taginput-container { .taginput-container {
border-radius: var(--tainacan-input-border-radius, 1px) !important; border-radius: var(--tainacan-input-border-radius, 1px) !important;
box-shadow: none !important; box-shadow: none !important;

View File

@ -20,10 +20,23 @@
@input="resetPage"> @input="resetPage">
<span class="check" /> <span class="check" />
<span class="control-label"> <span class="control-label">
<span class="checkbox-label-text">{{ option.label }}</span> <span
v-tooltip="{
delay: {
show: 800,
hide: 100,
},
content: option.label,
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''],
placement: 'auto-start'
}"
class="checkbox-label-text">
{{ option.label }}
</span>
<span <span
v-if="option.total_items != undefined" v-if="option.total_items != undefined"
class="has-text-gray">&nbsp;{{ "(" + option.total_items + ")" }}</span> class="facet-item-count has-text-gray">&nbsp;{{ "(" + option.total_items + ")" }}</span>
</span> </span>
</label> </label>
<button <button
@ -328,12 +341,27 @@
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: nowrap;
width: 100%; width: 100%;
align-items: center;
} }
.checkbox-label-text { .checkbox-label-text {
white-space: nowrap; white-space: wrap;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: hidden; overflow: hidden;
line-height: 1.45em; line-height: 1.45em;
break-inside: avoid; break-inside: avoid;
display: -webkit-box;
line-clamp: 2;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
} }
.facet-item-count {
margin-left: auto;
}
.b-checkbox:hover .facet-item-count,
.b-checkbox:focus .facet-item-count {
--tainacan-info-color: var(--tainacan-input-color);
}
</style> </style>

View File

@ -14,7 +14,7 @@
:aria-close-label="$i18n.get('remove_value')" :aria-close-label="$i18n.get('remove_value')"
:aria-labelledby="'filter-label-id-' + filter.id" :aria-labelledby="'filter-label-id-' + filter.id"
:class="{'has-selected': selected != undefined && selected != []}" :class="{'has-selected': selected != undefined && selected != []}"
:placeholder="$i18n.get('info_type_to_add_terms')" :placeholder="filter.placeholder ? filter.placeholder : $i18n.get('info_type_to_add_terms')"
check-infinite-scroll check-infinite-scroll
@typing="search" @typing="search"
@focus="($event) => { searchQuery = $event.target.value; performSearch(searchQuery) }" @focus="($event) => { searchQuery = $event.target.value; performSearch(searchQuery) }"

View File

@ -12,6 +12,7 @@ class TaxonomyCheckbox extends Filter_Type {
$this->set_name( __('Taxonomy Checkbox List', 'tainacan') ); $this->set_name( __('Taxonomy Checkbox List', 'tainacan') );
$this->set_supported_types(['term']); $this->set_supported_types(['term']);
$this->set_component('tainacan-filter-taxonomy-checkbox'); $this->set_component('tainacan-filter-taxonomy-checkbox');
$this->set_use_input_placeholder(false);
$this->set_preview_template(' $this->set_preview_template('
<div> <div>
<div> <div>

View File

@ -41,7 +41,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: activity.title, content: activity.title,
@ -61,7 +61,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: activity.user_name, content: activity.user_name,
@ -80,7 +80,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: activity.date, content: activity.date,

View File

@ -41,7 +41,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 120, hide: 120,
}, },
content: capability.display_name, content: capability.display_name,
@ -60,7 +60,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 120, hide: 120,
}, },
content: capability.description, content: capability.description,
@ -82,7 +82,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 120, hide: 120,
}, },
content: props['complete-roles-list'], content: props['complete-roles-list'],

View File

@ -204,7 +204,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: collection.name, content: collection.name,
@ -225,7 +225,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: (collection.description != undefined && collection.description != '') ? collection.description : `<span class='has-text-gray is-italic'>` + $i18n.get('label_description_not_provided') + `</span>`, content: (collection.description != undefined && collection.description != '') ? collection.description : `<span class='has-text-gray is-italic'>` + $i18n.get('label_description_not_provided') + `</span>`,
@ -246,7 +246,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: collection.modification_date, content: collection.modification_date,
@ -267,7 +267,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: collection.creation_date, content: collection.creation_date,
@ -288,7 +288,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: collection.author_name, content: collection.author_name,
@ -310,7 +310,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: getTotalItemsDetailed(collection.total_items), content: getTotalItemsDetailed(collection.total_items),

View File

@ -203,7 +203,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`), content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`),
@ -534,7 +534,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`), content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`),
@ -663,7 +663,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.description != undefined && item.description != '' ? item.description : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_description_not_provided') + `</span>`, content: item.description != undefined && item.description != '' ? item.description : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_description_not_provided') + `</span>`,
@ -678,7 +678,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.author_name != undefined ? item.author_name : '', content: item.author_name != undefined ? item.author_name : '',
@ -694,7 +694,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.creation_date != undefined ? parseDateToNavigatorLanguage(item.creation_date) : '', content: item.creation_date != undefined ? parseDateToNavigatorLanguage(item.creation_date) : '',
@ -775,7 +775,7 @@
v-if="collectionId != undefined && titleItemMetadatum" v-if="collectionId != undefined && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.metadata != undefined ? renderMetadata(item.metadata, titleItemMetadatum) : '', content: item.metadata != undefined ? renderMetadata(item.metadata, titleItemMetadatum) : '',
@ -791,7 +791,7 @@
v-if="collectionId == undefined && titleItemMetadatum" v-if="collectionId == undefined && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`), content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`),
@ -1063,7 +1063,7 @@
column.metadata_type_object.related_mapped_prop == 'title'" column.metadata_type_object.related_mapped_prop == 'title'"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined && item.title != '' ? item.title : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`, content: item.title != undefined && item.title != '' ? item.title : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`,
@ -1079,7 +1079,7 @@
column.metadata_type_object.related_mapped_prop == 'description'" column.metadata_type_object.related_mapped_prop == 'description'"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.description != undefined && item.description != '' ? item.description : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`, content: item.description != undefined && item.description != '' ? item.description : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`,
@ -1100,7 +1100,7 @@
column.metadatum !== 'row_description'" column.metadatum !== 'row_description'"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
popperClass: [ 'tainacan-tooltip', 'tooltip', column.metadata_type_object != undefined && column.metadata_type_object.component == 'tainacan-textarea' ? 'metadata-type-textarea' : '', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''], popperClass: [ 'tainacan-tooltip', 'tooltip', column.metadata_type_object != undefined && column.metadata_type_object.component == 'tainacan-textarea' ? 'metadata-type-textarea' : '', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''],
@ -1127,7 +1127,7 @@
v-if="column.metadatum == 'row_author'" v-if="column.metadatum == 'row_author'"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item[column.slug], content: item[column.slug],
@ -1142,7 +1142,7 @@
v-if="column.metadatum == 'row_modification'" v-if="column.metadatum == 'row_modification'"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: parseDateToNavigatorLanguage(item[column.slug]), content: parseDateToNavigatorLanguage(item[column.slug]),
@ -1157,7 +1157,7 @@
v-if="column.metadatum == 'row_creation'" v-if="column.metadatum == 'row_creation'"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: parseDateToNavigatorLanguage(item[column.slug]), content: parseDateToNavigatorLanguage(item[column.slug]),
@ -1317,7 +1317,7 @@
v-if="collectionId != undefined && titleItemMetadatum" v-if="collectionId != undefined && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.metadata != undefined ? renderMetadata(item.metadata, titleItemMetadatum) : '', content: item.metadata != undefined ? renderMetadata(item.metadata, titleItemMetadatum) : '',
@ -1333,7 +1333,7 @@
v-if="collectionId == undefined && titleItemMetadatum" v-if="collectionId == undefined && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`), content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`),
@ -1549,7 +1549,7 @@
v-if="collectionId != undefined && titleItemMetadatum" v-if="collectionId != undefined && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.metadata != undefined ? renderMetadata(item.metadata, titleItemMetadatum) : '', content: item.metadata != undefined ? renderMetadata(item.metadata, titleItemMetadatum) : '',
@ -1563,7 +1563,7 @@
v-if="collectionId == undefined && titleItemMetadatum" v-if="collectionId == undefined && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`), content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`),
@ -1792,7 +1792,7 @@
v-if="collectionId != undefined && titleItemMetadatum" v-if="collectionId != undefined && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.metadata != undefined ? renderMetadata(item.metadata, titleItemMetadatum) : '', content: item.metadata != undefined ? renderMetadata(item.metadata, titleItemMetadatum) : '',
@ -1808,7 +1808,7 @@
v-if="collectionId == undefined && titleItemMetadatum" v-if="collectionId == undefined && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`), content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`),
@ -1979,6 +1979,178 @@
</l-control> </l-control>
</l-map> </l-map>
</div> </div>
<!-- MOSAIC VIEW MODE -->
<ul
v-if="viewMode == 'mosaic'"
:class="{
'hide-items-selection': $adminOptions.hideItemsListSelection
}"
class="tainacan-mosaic-container">
<li
v-for="(item, index) of items"
:key="index"
:data-tainacan-item-id="item.id"
:style="{
'--tainacan-mosaic-item-width': getAcceptableWidthBasedOnRatio(item['thumbnail'], 'tainacan-large-full', 300),
'--tainacan-mosaic-item-height': $thumbHelper.getHeight(item['thumbnail'], 'tainacan-large-full', 300)
}">
<div
:class="{
'selected-mosaic-item': getSelectedItemChecked(item.id) == true
}"
class="tainacan-mosaic-item"
@click.left="onClickItem($event, item)"
@click.right="onRightClickItem($event, item)">
<!-- Thumbnail -->
<blur-hash-image
v-if="item.thumbnail != undefined"
class="tainacan-mosaic-item-thumbnail"
:width="$thumbHelper.getWidth(item['thumbnail'], 'tainacan-large-full', 320)"
:height="$thumbHelper.getHeight(item['thumbnail'], 'tainacan-large-full', 320)"
:hash="$thumbHelper.getBlurhashString(item['thumbnail'], 'tainacan-large-full')"
:src="$thumbHelper.getSrc(item['thumbnail'], 'tainacan-large-full', item.document_mimetype)"
:srcset="$thumbHelper.getSrcSet(item['thumbnail'], 'tainacan-large-full', item.document_mimetype)"
:alt="item.thumbnail_alt ? item.thumbnail_alt : $i18n.get('label_thumbnail')"
:transition-duration="500"
/>
<!-- Title -->
<div
class="metadata-title"
:style="{ 'padding-left': collectionId && !$adminOptions.hideItemsListSelection && ($adminOptions.itemsSingleSelectionMode || $adminOptions.itemsMultipleSelectionMode || (collection && collection.current_user_can_bulk_edit)) ? '1.75em' : '1.0em' }">
<!-- Checkbox -->
<!-- TODO: Remove v-if="collectionId" from this element when the bulk edit in repository is done -->
<div
v-if="collectionId && !$adminOptions.hideItemsListSelection && ($adminOptions.itemsSingleSelectionMode || $adminOptions.itemsMultipleSelectionMode || (collection && collection.current_user_can_bulk_edit))"
:class="{ 'is-selecting': isSelectingItems }"
class="mosaic-item-checkbox">
<label
tabindex="0"
:class="(!$adminOptions.itemsSingleSelectionMode ? 'b-checkbox checkbox' : 'b-radio radio') + ' is-small'">
<input
v-if="!$adminOptions.itemsSingleSelectionMode"
type="checkbox"
:checked="getSelectedItemChecked(item.id)"
@input="setSelectedItemChecked(item.id)">
<input
v-else
v-model="singleItemSelection"
type="radio"
name="item-single-selection"
:value="item.id">
<span class="check" />
<span class="control-label" />
<span class="sr-only">{{ $i18n.get('label_select_item') }}</span>
</label>
</div>
<p
v-tooltip="{
delay: {
show: 750,
hide: 100,
},
content: item.title != undefined ? item.title : '',
html: true,
placement: 'auto-start',
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
}">
<span
v-if="isOnAllItemsTabs && $statusHelper.hasIcon(item.status)"
v-tooltip="{
content: $i18n.get('status_' + item.status),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''],
placement: 'auto-start'
}"
class="icon has-text-gray">
<i
class="tainacan-icon tainacan-icon-1em"
:class="$statusHelper.getIcon(item.status)"
/>
</span>
{{ item.title != undefined ? item.title : '' }}
</p>
</div>
<!-- Actions -->
<div
v-if="item.current_user_can_edit && !$adminOptions.hideItemsListActionAreas"
class="actions-area"
:label="$i18n.get('label_actions')">
<a
v-if="!isOnTrash"
id="button-edit"
:aria-label="$i18n.getFrom('items','edit_item')"
@click.prevent.stop="goToItemEditPage(item)">
<span
v-tooltip="{
content: $i18n.get('edit'),
autoHide: true,
placement: 'auto',
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
}"
class="icon">
<i class="has-text-secondary tainacan-icon tainacan-icon-1-25em tainacan-icon-edit" />
</span>
</a>
<a
v-if="isOnTrash"
:aria-lavel="$i18n.get('label_button_untrash')"
@click.prevent.stop="untrashOneItem(item.id)">
<span
v-tooltip="{
content: $i18n.get('label_recover_from_trash'),
autoHide: true,
placement: 'auto',
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
}"
class="icon">
<i class="has-text-secondary tainacan-icon tainacan-icon-1-25em tainacan-icon-undo" />
</span>
</a>
<a
v-if="item.current_user_can_delete"
id="button-delete"
:aria-label="$i18n.get('label_button_delete')"
@click.prevent.stop="deleteOneItem(item.id)">
<span
v-tooltip="{
content: isOnTrash ? $i18n.get('label_delete_permanently') : $i18n.get('delete'),
autoHide: true,
placement: 'auto',
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
}"
class="icon">
<i
:class="{ 'tainacan-icon-delete': !isOnTrash, 'tainacan-icon-deleteforever': isOnTrash }"
class="has-text-secondary tainacan-icon tainacan-icon-1-25em" />
</span>
</a>
<a
v-if="!isOnTrash"
id="button-open-external"
:aria-label="$i18n.getFrom('items','view_item')"
target="_blank"
:href="item.url"
@click.stop="">
<span
v-tooltip="{
content: $i18n.get('label_item_page_on_website'),
autoHide: true,
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''],
placement: 'auto',
html: true
}"
class="icon">
<i class="tainacan-icon tainacan-icon-1-125em tainacan-icon-openurl" />
</span>
</a>
</div>
</div>
</li>
</ul>
</div> </div>
</div> </div>
</template> </template>
@ -2674,6 +2846,12 @@ export default {
duration: 3000 duration: 3000
}); });
} }
},
getAcceptableWidthBasedOnRatio(thumbnail, size, defaultSize) {
const width = this.$thumbHelper.getWidth(thumbnail, size, defaultSize);
const height = this.$thumbHelper.getHeight(thumbnail, size, defaultSize);
return (width / height) > 0.7 ? width : ( height * 0.7 );
} }
} }
} }
@ -2685,6 +2863,7 @@ export default {
@import "../../scss/_tables.scss"; @import "../../scss/_tables.scss";
@import "../../scss/_view-mode-cards.scss"; @import "../../scss/_view-mode-cards.scss";
@import "../../scss/_view-mode-masonry.scss"; @import "../../scss/_view-mode-masonry.scss";
@import "../../scss/_view-mode-mosaic.scss";
@import "../../scss/_view-mode-grid.scss"; @import "../../scss/_view-mode-grid.scss";
@import "../../scss/_view-mode-records.scss"; @import "../../scss/_view-mode-records.scss";
@import "../../scss/_view-mode-list.scss"; @import "../../scss/_view-mode-list.scss";

View File

@ -58,7 +58,7 @@
content: getPreviewTemplateContent(metadatum), content: getPreviewTemplateContent(metadatum),
html: true, html: true,
delay: { delay: {
shown: 0, show: 0,
hide: 100, hide: 100,
}, },
placement: 'top', placement: 'top',
@ -123,7 +123,7 @@
content: $i18n.get('info_create_section'), content: $i18n.get('info_create_section'),
html: true, html: true,
delay: { delay: {
shown: 0, show: 0,
hide: 100, hide: 100,
}, },
placement: 'top', placement: 'top',

View File

@ -73,7 +73,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: bgProcess.name ? bgProcess.name : $i18n.get('label_unnamed_process'), content: bgProcess.name ? bgProcess.name : $i18n.get('label_unnamed_process'),
@ -91,7 +91,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: bgProcess.progress_label ? bgProcess.progress_label : $i18n.get('label_no_details_of_process'), content: bgProcess.progress_label ? bgProcess.progress_label : $i18n.get('label_no_details_of_process'),
@ -111,7 +111,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: getDate(bgProcess.queued_on), content: getDate(bgProcess.queued_on),
@ -136,7 +136,7 @@
v-if=" bgProcess.status === 'running' " v-if=" bgProcess.status === 'running' "
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_stop_process'), content: $i18n.get('label_stop_process'),
@ -152,7 +152,7 @@
v-if=" ( bgProcess.status === 'finished' && !bgProcess.error_log ) || bgProcess.status === null" v-if=" ( bgProcess.status === 'finished' && !bgProcess.error_log ) || bgProcess.status === null"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_process_completed'), content: $i18n.get('label_process_completed'),
@ -167,7 +167,7 @@
v-if=" bgProcess.status === 'finished-errors' || ( bgProcess.done > 0 && bgProcess.error_log && bgProcess.status === 'finished' ) " v-if=" bgProcess.status === 'finished-errors' || ( bgProcess.done > 0 && bgProcess.error_log && bgProcess.status === 'finished' ) "
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_process_completed_with_errors'), content: $i18n.get('label_process_completed_with_errors'),
@ -182,7 +182,7 @@
v-if=" bgProcess.status === 'cancelled' " v-if=" bgProcess.status === 'cancelled' "
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_process_cancelled'), content: $i18n.get('label_process_cancelled'),
@ -197,7 +197,7 @@
v-if=" bgProcess.status === 'paused' " v-if=" bgProcess.status === 'paused' "
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_process_paused'), content: $i18n.get('label_process_paused'),
@ -212,7 +212,7 @@
v-if=" bgProcess.status === 'waiting' " v-if=" bgProcess.status === 'waiting' "
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_process_waiting'), content: $i18n.get('label_process_waiting'),
@ -227,7 +227,7 @@
v-if=" bgProcess.status === 'waiting' " v-if=" bgProcess.status === 'waiting' "
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_delete_process'), content: $i18n.get('label_delete_process'),
@ -243,7 +243,7 @@
v-if="bgProcess.status === 'errored'" v-if="bgProcess.status === 'errored'"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_process_failed'), content: $i18n.get('label_process_failed'),
@ -306,7 +306,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: getDate(bgProcess.processed_last), content: getDate(bgProcess.processed_last),

View File

@ -93,7 +93,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: relatedItem.title != undefined && relatedItem.title != '' ? relatedItem.title : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`, content: relatedItem.title != undefined && relatedItem.title != '' ? relatedItem.title : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`,
@ -117,7 +117,7 @@
<span <span
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 100, hide: 100,
}, },
content: $i18n.get('edit'), content: $i18n.get('edit'),

View File

@ -131,7 +131,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: taxonomy.name, content: taxonomy.name,
@ -150,7 +150,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: taxonomy.description != undefined && taxonomy.description != '' ? taxonomy.description : `<span class='has-text-gray is-italic'>` + $i18n.get('label_description_not_provided') + `</span>`, content: taxonomy.description != undefined && taxonomy.description != '' ? taxonomy.description : `<span class='has-text-gray is-italic'>` + $i18n.get('label_description_not_provided') + `</span>`,
@ -169,7 +169,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: (taxonomy.collections != undefined && taxonomy.collections.length != undefined && taxonomy.collections.length > 0) ? renderListOfCollections(taxonomy.collections, taxonomy.metadata_by_collection) : $i18n.get('label_no_collections_using_taxonomy'), content: (taxonomy.collections != undefined && taxonomy.collections.length != undefined && taxonomy.collections.length > 0) ? renderListOfCollections(taxonomy.collections, taxonomy.metadata_by_collection) : $i18n.get('label_no_collections_using_taxonomy'),
@ -191,7 +191,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: getTotalTermsDetailed(taxonomy.total_terms), content: getTotalTermsDetailed(taxonomy.total_terms),

View File

@ -234,7 +234,7 @@
let val = this.valueComponent; let val = this.valueComponent;
if ((!Array.isArray(val) || val.length == 0) && this.itemMetadatum.metadatum.multiple === 'no') { if ((!Array.isArray(val) || val.length == 0) && this.itemMetadatum.metadatum.multiple === 'no') {
tainacanApi.patch(`/item/${this.itemMetadatum.item.id}/metadata/${this.itemMetadatum.metadatum.id}`, { tainacanApi.put(`/item/${this.itemMetadatum.item.id}/metadata/${this.itemMetadatum.metadatum.id}`, {
values: term.id, values: term.id,
}).then(() => { }).then(() => {
this.isAddingNewTermVaue = false; this.isAddingNewTermVaue = false;
@ -244,7 +244,7 @@
} else { } else {
val = val ? val : []; val = val ? val : [];
val.push( this.getComponent == ('tainacan-taxonomy-checkbox' || 'tainacan-taxonomy-radio') ? term.id : {'label': term.name, 'value': term.id} ); val.push( this.getComponent == ('tainacan-taxonomy-checkbox' || 'tainacan-taxonomy-radio') ? term.id : {'label': term.name, 'value': term.id} );
tainacanApi.patch(`/item/${this.itemMetadatum.item.id}/metadata/${this.itemMetadatum.metadatum.id}`, { tainacanApi.put(`/item/${this.itemMetadatum.item.id}/metadata/${this.itemMetadatum.metadatum.id}`, {
values: val, values: val,
}).then(() => { }).then(() => {
this.isAddingNewTermVaue = false; this.isAddingNewTermVaue = false;

View File

@ -242,7 +242,7 @@
placement: 'auto', placement: 'auto',
popperClass: ['tainacan-tooltip', 'tooltip'], popperClass: ['tainacan-tooltip', 'tooltip'],
triggers: [], triggers: [],
shown: bulkEditionProcedures[criterion].tooltipShow show: bulkEditionProcedures[criterion].tooltipShow
}" }"
class="icon"> class="icon">
<i class="has-text-success tainacan-icon tainacan-icon-1-25em tainacan-icon-approvedcircle" /> <i class="has-text-success tainacan-icon tainacan-icon-1-25em tainacan-icon-approvedcircle" />

View File

@ -41,7 +41,7 @@
<a <a
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_copy_link_url'), content: $i18n.get('label_copy_link_url'),
@ -75,7 +75,7 @@
<a <a
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_open_externally'), content: $i18n.get('label_open_externally'),
@ -140,7 +140,7 @@
<label <label
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: selectedExposer.name + (exposerMapper.name != undefined ? ': ' + exposerMapper.name + ' ' + $i18n.get('label_mapper') : ''), content: selectedExposer.name + (exposerMapper.name != undefined ? ': ' + exposerMapper.name + ' ' + $i18n.get('label_mapper') : ''),
@ -171,7 +171,7 @@
<a <a
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_copy_link_url'), content: $i18n.get('label_copy_link_url'),
@ -205,7 +205,7 @@
<a <a
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_open_externally'), content: $i18n.get('label_open_externally'),

View File

@ -51,7 +51,7 @@
type="submit" type="submit"
class="button is-success" class="button is-success"
@click="onConfirm(); $emit('close');"> @click="onConfirm(); $emit('close');">
{{ $i18n.get('continue') }} {{ confirmText ? confirmText : $i18n.get('continue') }}
</button> </button>
</footer> </footer>
</div> </div>
@ -66,6 +66,10 @@
title: String, title: String,
message: String, message: String,
icon: String, icon: String,
confirmText: {
type: String,
default: ''
},
onConfirm: { onConfirm: {
type: Function, type: Function,
default: () => {} default: () => {}

View File

@ -7,7 +7,7 @@
popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-helper-tooltip', extraClasses], popperClass: ['tainacan-tooltip', 'tooltip', 'tainacan-helper-tooltip', extraClasses],
html: true, html: true,
delay: { delay: {
shown: 0, show: 0,
hide: 100, hide: 100,
} }
}" }"
@ -30,8 +30,8 @@ export default {
}, },
computed: { computed: {
getHelperTooltipContent() { getHelperTooltipContent() {
return `<h5>` + this.title + `</h5> return ( this.title ? ( `<p style="font-weight: bold; color: var(--tainacan-secondary);">` + this.title + `</p>` ) : '' ) +
<p>` + ((this.message != '' && this.message != undefined) ? this.message : this.$i18n.get('info_no_description_provided')) + `</p>`; `<p style="color: var(--tainacan-info-color);">` + ((this.message != '' && this.message != undefined) ? this.message : this.$i18n.get('info_no_description_provided')) + `</p>`;
} }
} }
} }

View File

@ -5,7 +5,7 @@
<v-tooltip <v-tooltip
:popper-class="['tainacan-tooltip', 'tooltip', 'tainacan-helper-tooltip', 'is-danger']" :popper-class="['tainacan-tooltip', 'tooltip', 'tainacan-helper-tooltip', 'is-danger']"
delay="{ delay="{
shown: 0, show: 0,
hide: 400, hide: 400,
}"> }">
<a class="help-button has-text-danger"> <a class="help-button has-text-danger">

View File

@ -16,9 +16,9 @@
</h3> </h3>
<button <button
v-if="!isLoadingFilters && v-if="!hideFilterCollapses && !isLoadingFilters && (
((filters.length >= 0 && ( filters.length >= 0 && isRepositoryLevel ) || filters.length > 0
isRepositoryLevel) || filters.length > 0)" )"
aria-controls="filters-items-list" aria-controls="filters-items-list"
:aria-expanded="!collapseAll" :aria-expanded="!collapseAll"
class="link-style collapse-all" class="link-style collapse-all"
@ -33,7 +33,7 @@
</span> </span>
</button> </button>
<br> <br v-if="!hideFilterCollapses">
<filters-tags-list <filters-tags-list
v-if="filtersAsModal && hasFiltered" v-if="filtersAsModal && hasFiltered"
@ -56,7 +56,7 @@
v-if="taxonomyFilter.length > 0 && taxonomyFiltersCollectionNames != undefined && taxonomyFiltersCollectionNames[key] != undefined" v-if="taxonomyFilter.length > 0 && taxonomyFiltersCollectionNames != undefined && taxonomyFiltersCollectionNames[key] != undefined"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_filters_from') + ' ' + taxonomyFiltersCollectionNames[key] + ': ', content: $i18n.get('label_filters_from') + ' ' + taxonomyFiltersCollectionNames[key] + ': ',
@ -86,7 +86,8 @@
:expand-all="!collapseAll" :expand-all="!collapseAll"
:is-repository-level="key == 'repository-filters'" :is-repository-level="key == 'repository-filters'"
:filters-as-modal="filtersAsModal" :filters-as-modal="filtersAsModal"
:is-mobile-screen="isMobileScreen" /> :is-mobile-screen="isMobileScreen"
:hide-collapses="hideFilterCollapses" />
</template> </template>
<hr v-if="taxonomyFilter.length > 1"> <hr v-if="taxonomyFilter.length > 1">
</div> </div>
@ -99,7 +100,7 @@
v-if="taxonomyFilter.length > 0 && taxonomyFiltersCollectionNames != undefined && taxonomyFiltersCollectionNames[key] != undefined" v-if="taxonomyFilter.length > 0 && taxonomyFiltersCollectionNames != undefined && taxonomyFiltersCollectionNames[key] != undefined"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_filters_from') + ' ' + taxonomyFiltersCollectionNames[key] + ': ', content: $i18n.get('label_filters_from') + ' ' + taxonomyFiltersCollectionNames[key] + ': ',
@ -129,7 +130,8 @@
:expand-all="!collapseAll" :expand-all="!collapseAll"
:is-repository-level="key == 'repository-filters'" :is-repository-level="key == 'repository-filters'"
:filters-as-modal="filtersAsModal" :filters-as-modal="filtersAsModal"
:is-mobile-screen="isMobileScreen" /> :is-mobile-screen="isMobileScreen"
:hide-collapses="hideFilterCollapses" />
</template> </template>
<hr v-if="taxonomyFilter.length > 1"> <hr v-if="taxonomyFilter.length > 1">
</div> </div>
@ -146,7 +148,7 @@
v-if="repositoryCollectionFilter.length > 0 && repositoryCollectionNames != undefined && repositoryCollectionNames[key] != undefined" v-if="repositoryCollectionFilter.length > 0 && repositoryCollectionNames != undefined && repositoryCollectionNames[key] != undefined"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_filters_from') + ' ' + repositoryCollectionNames[key] + ': ', content: $i18n.get('label_filters_from') + ' ' + repositoryCollectionNames[key] + ': ',
@ -176,7 +178,8 @@
:expand-all="!collapseAll" :expand-all="!collapseAll"
:is-repository-level="key == 'repository-filters'" :is-repository-level="key == 'repository-filters'"
:filters-as-modal="filtersAsModal" :filters-as-modal="filtersAsModal"
:is-mobile-screen="isMobileScreen" /> :is-mobile-screen="isMobileScreen"
:hide-collapses="hideFilterCollapses" />
</template> </template>
<hr v-if="repositoryCollectionFilters.length > 1"> <hr v-if="repositoryCollectionFilters.length > 1">
</div> </div>
@ -189,7 +192,7 @@
v-if="repositoryCollectionFilter.length > 0 && repositoryCollectionNames != undefined && repositoryCollectionNames[key] != undefined" v-if="repositoryCollectionFilter.length > 0 && repositoryCollectionNames != undefined && repositoryCollectionNames[key] != undefined"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_filters_from') + ' ' + repositoryCollectionNames[key] + ': ', content: $i18n.get('label_filters_from') + ' ' + repositoryCollectionNames[key] + ': ',
@ -219,7 +222,8 @@
:expand-all="!collapseAll" :expand-all="!collapseAll"
:is-repository-level="key == 'repository-filters'" :is-repository-level="key == 'repository-filters'"
:filters-as-modal="filtersAsModal" :filters-as-modal="filtersAsModal"
:is-mobile-screen="isMobileScreen" /> :is-mobile-screen="isMobileScreen"
:hide-collapses="hideFilterCollapses" />
</template> </template>
<hr v-if="repositoryCollectionFilters.length > 1"> <hr v-if="repositoryCollectionFilters.length > 1">
</div> </div>
@ -237,7 +241,8 @@
:expand-all="!collapseAll" :expand-all="!collapseAll"
:is-repository-level="isRepositoryLevel" :is-repository-level="isRepositoryLevel"
:filters-as-modal="filtersAsModal" :filters-as-modal="filtersAsModal"
:is-mobile-screen="isMobileScreen" /> :is-mobile-screen="isMobileScreen"
:hide-collapses="hideFilterCollapses" />
</template> </template>
</div> </div>
<section <section
@ -293,7 +298,8 @@
filtersAsModal: Boolean, filtersAsModal: Boolean,
hasFiltered: Boolean, hasFiltered: Boolean,
isLoadingItems: Boolean, isLoadingItems: Boolean,
isMobileScreen: false isMobileScreen: false,
hideFilterCollapses: false
}, },
emits: [ emits: [
'update-is-loading-items-state' 'update-is-loading-items-state'
@ -489,6 +495,12 @@
.filters-components-list { .filters-components-list {
margin-bottom: 64px; margin-bottom: 64px;
} }
@supports (contain: inline-size) {
.filters-components-list {
container-type: inline-size;
container-name: filterscomponentslist;
}
}
.collection-name { .collection-name {
color: var(--tainacan-heading-color); color: var(--tainacan-heading-color);
font-size: 0.875em; font-size: 0.875em;

View File

@ -113,7 +113,8 @@
taxonomy: tag.taxonomy, taxonomy: tag.taxonomy,
metadatumName: this.getMetadatumName(tag), metadatumName: this.getMetadatumName(tag),
metadatumId: tag.metadatumId, metadatumId: tag.metadatumId,
argType: tag.argType argType: tag.argType,
secondaryMetadatumId: tag.secondaryMetadatumId
}); });
} }
} else { } else {
@ -124,7 +125,8 @@
taxonomy: tag.taxonomy, taxonomy: tag.taxonomy,
metadatumName: this.getMetadatumName(tag), metadatumName: this.getMetadatumName(tag),
metadatumId: tag.metadatumId, metadatumId: tag.metadatumId,
argType: tag.argType argType: tag.argType,
secondaryMetadatumId: tag.secondaryMetadatumId
}); });
} }
}); });
@ -168,7 +170,7 @@
...mapGetters('search',[ ...mapGetters('search',[
'getFilterTags' 'getFilterTags'
]), ]),
removeMetaQuery({ filterId, value, singleLabel, label, taxonomy, metadatumId, metadatumName, argType }) { removeMetaQuery({ filterId, value, singleLabel, label, taxonomy, metadatumId, metadatumName, argType, secondaryMetadatumId }) {
this.$eventBusSearch.resetPageOnStore(); this.$eventBusSearch.resetPageOnStore();
this.$eventBusSearch.removeMetaFromFilterTag({ this.$eventBusSearch.removeMetaFromFilterTag({
filterId: filterId, filterId: filterId,
@ -178,7 +180,8 @@
taxonomy: taxonomy, taxonomy: taxonomy,
metadatumId: metadatumId, metadatumId: metadatumId,
metadatumName:metadatumName, metadatumName:metadatumName,
argType: argType argType: argType,
secondaryMetadatumId: secondaryMetadatumId
}); });
}, },
clearAllFilters() { clearAllFilters() {

View File

@ -39,7 +39,8 @@ export default {
label: filterTag.singleLabel ? filterTag.singleLabel : filterTag.label, label: filterTag.singleLabel ? filterTag.singleLabel : filterTag.label,
isMultiValue: filterTag.singleLabel ? false : true, isMultiValue: filterTag.singleLabel ? false : true,
taxonomy: filterTag.taxonomy, taxonomy: filterTag.taxonomy,
value: filterTag.value value: filterTag.value,
secondaryMetadatumId: filterTag.secondaryMetadatumId
}); });
} else { } else {
app.config.globalProperties.$store.dispatch('search/removeMetaQuery', { app.config.globalProperties.$store.dispatch('search/removeMetaQuery', {
@ -47,7 +48,8 @@ export default {
label: filterTag.singleLabel ? filterTag.singleLabel : filterTag.label, label: filterTag.singleLabel ? filterTag.singleLabel : filterTag.label,
isMultiValue: filterTag.singleLabel ? false : true, isMultiValue: filterTag.singleLabel ? false : true,
metadatum_id: filterTag.metadatumId, metadatum_id: filterTag.metadatumId,
value: filterTag.value value: filterTag.value,
secondaryMetadatumId: filterTag.secondaryMetadatumId
}); });
} }
} else { } else {

View File

@ -46,7 +46,7 @@ export const fetchProcesses = ({ commit }, {page, processesPerPage, shouldUpdate
export const updateProcess = ({ commit }, { id, status }) => { export const updateProcess = ({ commit }, { id, status }) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacanApi.patch(`/bg-processes/${id}/`, { axios.tainacanApi.put(`/bg-processes/${id}/`, {
status: status, status: status,
}) })
.then( res => { .then( res => {

View File

@ -3,7 +3,7 @@ import axios from '../../../axios'
// ROLES // ROLES
export const addCapabilityToRole = ({ commit }, { capabilityKey, role }) => { export const addCapabilityToRole = ({ commit }, { capabilityKey, role }) => {
return new Promise(( resolve, reject ) => { return new Promise(( resolve, reject ) => {
axios.tainacanApi.patch('/roles/' + role + '?add_cap=' + capabilityKey) axios.tainacanApi.put('/roles/' + role + '?add_cap=' + capabilityKey)
.then( res => { .then( res => {
let role = res.data; let role = res.data;
commit('addCapabilityToRole', {capabilityKey, role }); commit('addCapabilityToRole', {capabilityKey, role });
@ -17,7 +17,7 @@ export const addCapabilityToRole = ({ commit }, { capabilityKey, role }) => {
export const removeCapabilityFromRole = ({ commit }, { capabilityKey, role }) => { export const removeCapabilityFromRole = ({ commit }, { capabilityKey, role }) => {
return new Promise(( resolve, reject ) => { return new Promise(( resolve, reject ) => {
axios.tainacanApi.patch('/roles/' + role + '?remove_cap=' + capabilityKey) axios.tainacanApi.put('/roles/' + role + '?remove_cap=' + capabilityKey)
.then( res => { .then( res => {
let role = res.data; let role = res.data;
commit('removeCapabilityFromRole', {capabilityKey, role }); commit('removeCapabilityFromRole', {capabilityKey, role });
@ -79,7 +79,7 @@ export const updateRole = ({ commit }, role) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacanApi.patch('/roles/' + role.slug, role) axios.tainacanApi.put('/roles/' + role.slug, role)
.then(res => { .then(res => {
const updatedRole = res.data const updatedRole = res.data
commit('setRole', updatedRole); commit('setRole', updatedRole);

View File

@ -348,7 +348,7 @@ export const updateCollection = ({ commit }, {
collection collection
}) => { }) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacanApi.patch('/collections/' + collection_id + '?context=edit', collection).then( res => { axios.tainacanApi.put('/collections/' + collection_id + '?context=edit', collection).then( res => {
commit('setCollection', collection); commit('setCollection', collection);
resolve( res.data ); resolve( res.data );
}).catch( error => { }).catch( error => {
@ -416,7 +416,7 @@ export const fetchAttachments = ({ commit }, collection_id) => {
export const updateThumbnail = ({ commit }, { collectionId, thumbnailId }) => { export const updateThumbnail = ({ commit }, { collectionId, thumbnailId }) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacanApi.patch('/collections/' + collectionId + '?context=edit', { axios.tainacanApi.put('/collections/' + collectionId + '?context=edit', {
_thumbnail_id: thumbnailId _thumbnail_id: thumbnailId
}).then( res => { }).then( res => {
let collection = res.data let collection = res.data
@ -431,7 +431,7 @@ export const updateThumbnail = ({ commit }, { collectionId, thumbnailId }) => {
export const updateHeaderImage = ({ commit }, { collectionId, headerImageId }) => { export const updateHeaderImage = ({ commit }, { collectionId, headerImageId }) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacanApi.patch('/collections/' + collectionId + '?context=edit', { axios.tainacanApi.put('/collections/' + collectionId + '?context=edit', {
header_image_id: headerImageId + '' header_image_id: headerImageId + ''
}).then( res => { }).then( res => {
let collection = res.data let collection = res.data

View File

@ -27,7 +27,7 @@ export const createExporterSession = ({commit}, slug) => {
export const updateExporterSession = ({commit}, exporterSessionUpdated) => { export const updateExporterSession = ({commit}, exporterSessionUpdated) => {
return new Promise(( resolve, reject ) => { return new Promise(( resolve, reject ) => {
tainacanApi.patch(`/exporters/session/${exporterSessionUpdated.id}`, exporterSessionUpdated.body) tainacanApi.put(`/exporters/session/${exporterSessionUpdated.id}`, exporterSessionUpdated.body)
.then(response => { .then(response => {
commit('setExporterSession'); commit('setExporterSession');
resolve( response.data ); resolve( response.data );

View File

@ -128,7 +128,7 @@ export const addTemporaryFilter = ({ commit }, filter ) => {
export const updateCollectionFiltersOrder = ({ commit }, { collectionId, filtersOrder }) => { export const updateCollectionFiltersOrder = ({ commit }, { collectionId, filtersOrder }) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacanApi.patch('/collections/' + collectionId + '/filters_order?context=edit', { axios.tainacanApi.put('/collections/' + collectionId + '/filters_order?context=edit', {
filters_order: filtersOrder filters_order: filtersOrder
}).then( res => { }).then( res => {
commit('collection/setCollection', res.data, { root: true }); commit('collection/setCollection', res.data, { root: true });

View File

@ -8,7 +8,7 @@ export const updateItemMetadatum = ({ commit }, { item_id, metadatum_id, values,
body['parent_meta_id'] = parent_meta_id; body['parent_meta_id'] = parent_meta_id;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacanApi.patch(`/item/${item_id}/metadata/${metadatum_id}`, body) axios.tainacanApi.put(`/item/${item_id}/metadata/${metadatum_id}`, body)
.then( res => { .then( res => {
let itemMetadatum = res.data; let itemMetadatum = res.data;
commit('setSingleMetadatum', itemMetadatum); commit('setSingleMetadatum', itemMetadatum);
@ -45,7 +45,7 @@ export const fetchItemMetadata = ({ commit }, item_id) => {
export const fetchCompoundFirstParentMetaId = ({ commit }, { item_id, metadatum_id }) => { export const fetchCompoundFirstParentMetaId = ({ commit }, { item_id, metadatum_id }) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacanApi.patch(`/item/${item_id}/metadata/${metadatum_id}`, { value: [] }) axios.tainacanApi.put(`/item/${item_id}/metadata/${metadatum_id}`, { value: [] })
.then( res => { .then( res => {
const parentMetaId = res.data.parent_meta_id; const parentMetaId = res.data.parent_meta_id;
resolve(parentMetaId); resolve(parentMetaId);
@ -157,7 +157,7 @@ export const sendItem = ( { commit }, item) => {
export const updateItem = ({ commit }, item) => { export const updateItem = ({ commit }, item) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacanApi.patch('/items/' + item.id, item) axios.tainacanApi.put('/items/' + item.id, item)
.then( res => { .then( res => {
commit('setItem', res.data); commit('setItem', res.data);
commit('setLastUpdated'); commit('setLastUpdated');
@ -191,7 +191,7 @@ export const updateItemDocument = ({ commit }, { item_id, document, document_typ
params['document_options'] = document_options; params['document_options'] = document_options;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacanApi.patch('/items/' + item_id, params).then( res => { axios.tainacanApi.put('/items/' + item_id, params).then( res => {
let item = res.data; let item = res.data;
commit('setItem', item); commit('setItem', item);
@ -246,7 +246,7 @@ export const sendAttachment = ( { commit }, { item_id, file }) => {
export const removeAttachmentFromItem = ( { commit }, attachmentId) => { export const removeAttachmentFromItem = ( { commit }, attachmentId) => {
commit('cleanAttachment'); commit('cleanAttachment');
return new Promise(( resolve, reject ) => { return new Promise(( resolve, reject ) => {
axios.wpApi.patch('/media/' + attachmentId, { axios.wpApi.put('/media/' + attachmentId, {
post: 0 post: 0
}) })
.then( res => { .then( res => {
@ -306,7 +306,7 @@ export const fetchAttachments = ({ commit }, { page, attachmentsPerPage, itemId,
export const updateThumbnail = ({ commit }, { itemId, thumbnailId, thumbnailAlt }) => { export const updateThumbnail = ({ commit }, { itemId, thumbnailId, thumbnailAlt }) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacanApi.patch('/items/' + itemId, { axios.tainacanApi.put('/items/' + itemId, {
_thumbnail_id: thumbnailId _thumbnail_id: thumbnailId
}).then( res => { }).then( res => {
let item = res.data let item = res.data
@ -322,7 +322,7 @@ export const updateThumbnail = ({ commit }, { itemId, thumbnailId, thumbnailAlt
export const updateThumbnailAlt = ({ commit }, { thumbnailId, thumbnailAlt }) => { export const updateThumbnailAlt = ({ commit }, { thumbnailId, thumbnailAlt }) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.wpApi.patch('/media/' + thumbnailId + '?force=true', { axios.wpApi.put('/media/' + thumbnailId + '?force=true', {
alt_text: thumbnailAlt alt_text: thumbnailAlt
}).then( res => { }).then( res => {
let thumbnail = res.data; let thumbnail = res.data;

View File

@ -202,7 +202,7 @@ export const cleanMetadata = ({commit}) => {
export const updateCollectionMetadataOrder = ({ commit }, { collectionId, metadataOrder, metadataSectionId }) => { export const updateCollectionMetadataOrder = ({ commit }, { collectionId, metadataOrder, metadataSectionId }) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacanApi.patch('/collections/' + collectionId + '/metadata_section/' + metadataSectionId + '/metadata_order?context=edit', { axios.tainacanApi.put('/collections/' + collectionId + '/metadata_section/' + metadataSectionId + '/metadata_order?context=edit', {
metadata_order: metadataOrder metadata_order: metadataOrder
}).then(res => { }).then(res => {
commit('collection/setCollection', res.data, { root: true }); commit('collection/setCollection', res.data, { root: true });
@ -390,7 +390,7 @@ export const updateMetadataSections = ({commit}, metadataSections) => {
export const updateCollectionMetadataSectionsOrder = ({ commit }, {collectionId, metadataSectionsOrder }) => { export const updateCollectionMetadataSectionsOrder = ({ commit }, {collectionId, metadataSectionsOrder }) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
axios.tainacanApi.patch('/collections/' + collectionId + '/metadata_section_order?context=edit', { axios.tainacanApi.put('/collections/' + collectionId + '/metadata_section_order?context=edit', {
metadata_section_order: metadataSectionsOrder metadata_section_order: metadataSectionsOrder
}).then(res => { }).then(res => {
commit('collection/setCollection', res.data, { root: true }); commit('collection/setCollection', res.data, { root: true });

View File

@ -21,52 +21,39 @@ export const setAdvancedSearchQuery = (state, advancedSearchQuery) => {
export const addMetaQuery = ( state, filter ) => { export const addMetaQuery = ( state, filter ) => {
state.postquery.metaquery = ( ! state.postquery.metaquery || state.postquery.metaquery.length == undefined ) ? [] : state.postquery.metaquery; state.postquery.metaquery = ( ! state.postquery.metaquery || state.postquery.metaquery.length == undefined ) ? [] : state.postquery.metaquery;
let metaquery = {
key: filter.metadatum_id,
value: filter.value
}
if ( filter.compare )
metaquery.compare = filter.compare;
if ( filter.type )
metaquery.type = filter.type;
if ( filter.secondary )
metaquery.secondary = filter.secondary;
let index = state.postquery.metaquery.findIndex( item => item.key === filter.metadatum_id); let index = state.postquery.metaquery.findIndex( item => item.key === filter.metadatum_id);
if ( index >= 0 ) { if ( index >= 0 )
Object.assign( Object.assign( state.postquery.metaquery, { [index]: metaquery } );
state.postquery.metaquery, else
{ state.postquery.metaquery.push(metaquery);
[index]: {
key: filter.metadatum_id,
value: filter.value,
compare: filter.compare,
type: filter.type
}
}
);
} else {
state.postquery.metaquery.push({
key: filter.metadatum_id,
value: filter.value,
compare: filter.compare,
type: filter.type
});
}
}; };
export const addTaxQuery = ( state, filter ) => { export const addTaxQuery = ( state, filter ) => {
state.postquery.taxquery = ( ! state.postquery.taxquery || state.postquery.taxquery.length == undefined ) ? [] : state.postquery.taxquery; state.postquery.taxquery = ( ! state.postquery.taxquery || state.postquery.taxquery.length == undefined ) ? [] : state.postquery.taxquery;
let index = state.postquery.taxquery.findIndex( item => item.taxonomy === filter.taxonomy); let taxquery = {
taxonomy: filter.taxonomy,
terms: filter.terms
}
if ( filter.compare )
taxquery.compare = filter.compare;
if ( index >= 0 ) { let index = state.postquery.taxquery.findIndex( item => item.taxonomy === filter.taxonomy);
Object.assign( if ( index >= 0 )
state.postquery.taxquery, Object.assign( state.postquery.taxquery, { [index]: taxquery } );
{ else
[index]: { state.postquery.taxquery.push(taxquery);
taxonomy: filter.taxonomy,
terms: filter.terms,
compare: filter.compare
}
}
);
} else {
state.postquery.taxquery.push({
taxonomy: filter.taxonomy,
terms: filter.terms,
compare: filter.compare
});
}
}; };
export const addFetchOnly = ( state, metadatum ) => { export const addFetchOnly = ( state, metadatum ) => {
@ -111,6 +98,20 @@ export const removeMetaQuery = ( state, filter ) => {
state.postquery.metaquery[index].value.splice(otherIndex, 1) state.postquery.metaquery[index].value.splice(otherIndex, 1)
} else } else
state.postquery.metaquery.splice(index, 1); state.postquery.metaquery.splice(index, 1);
// Handles removing metaqueries from secondary filter metadata
if ( filter.secondaryMetadatumId ) {
let secondaryIndex = state.postquery.metaquery.findIndex( item => item.key == filter.secondaryMetadatumId);
if ( secondaryIndex >= 0 ) {
if ( !filter.isMultiValue && Array.isArray(state.postquery.metaquery[secondaryIndex].value) && state.postquery.metaquery[secondaryIndex].value.length > 1 ) {
let otherSecondaryIndex = state.postquery.metaquery[secondaryIndex].value.findIndex(item => item == filter.value);
if ( otherSecondaryIndex >= 0 )
state.postquery.metaquery[secondaryIndex].value.splice(otherSecondaryIndex, 1)
} else
state.postquery.metaquery.splice(secondaryIndex, 1);
}
}
} }
}; };
@ -201,7 +202,8 @@ export const setFilterTags = ( state, filterArguments ) => {
) ? aFilterArgument.metadatum.metadata_type_object.options.taxonomy : '', ) ? aFilterArgument.metadatum.metadata_type_object.options.taxonomy : '',
argType: aFilterArgument.arg_type ? aFilterArgument.arg_type : '', argType: aFilterArgument.arg_type ? aFilterArgument.arg_type : '',
metadatumId: (aFilterArgument.filter && aFilterArgument.metadatum.metadatum_id) ? aFilterArgument.metadatum.metadatum_id : (aFilterArgument.metadatum.id || ''), metadatumId: (aFilterArgument.filter && aFilterArgument.metadatum.metadatum_id) ? aFilterArgument.metadatum.metadatum_id : (aFilterArgument.metadatum.id || ''),
metadatumName: (aFilterArgument.filter && aFilterArgument.filter.name) ? aFilterArgument.filter.name : (aFilterArgument.metadatum.name || '') metadatumName: (aFilterArgument.filter && aFilterArgument.filter.name) ? aFilterArgument.filter.name : (aFilterArgument.metadatum.name || ''),
secondaryMetadatumId: (aFilterArgument.filter && aFilterArgument.filter.filter_type_options && aFilterArgument.filter.filter_type_options.secondary_filter_metadatum_id) ? aFilterArgument.filter.filter_type_options.secondary_filter_metadatum_id : '',
} }
}); });
state.filter_tags = filterTags; state.filter_tags = filterTags;

View File

@ -33,7 +33,7 @@ export const deleteTaxonomy = ({ commit }, { taxonomyId, isPermanently }) => {
export const updateTaxonomy = ({ commit }, taxonomy) => { export const updateTaxonomy = ({ commit }, taxonomy) => {
return new Promise(( resolve, reject ) => { return new Promise(( resolve, reject ) => {
axios.tainacanApi.patch(`/taxonomies/${taxonomy.taxonomyId}`, taxonomy) axios.tainacanApi.put(`/taxonomies/${taxonomy.taxonomyId}`, taxonomy)
.then( res => { .then( res => {
let taxonomy = res.data; let taxonomy = res.data;
commit('setTaxonomy', taxonomy); commit('setTaxonomy', taxonomy);
@ -191,7 +191,7 @@ export const updateTerm = ({}, { taxonomyId, term, itemId, metadatumId }) => {
term['metadatum_id'] = metadatumId; term['metadatum_id'] = metadatumId;
return new Promise(( resolve, reject ) => { return new Promise(( resolve, reject ) => {
axios.tainacanApi.patch(`/taxonomy/${taxonomyId}/terms/${term.id}`, term) axios.tainacanApi.put(`/taxonomy/${taxonomyId}/terms/${term.id}`, term)
.then( res => { .then( res => {
const updatedTerm = res.data; const updatedTerm = res.data;
resolve( updatedTerm ); resolve( updatedTerm );
@ -254,7 +254,7 @@ export const changeTermsParent = ({}, { taxonomyId, newParentTerm, terms, parent
query += `&include=${terms}`; query += `&include=${terms}`;
return new Promise(( resolve, reject ) => { return new Promise(( resolve, reject ) => {
axios.tainacanApi.patch(`/taxonomy/${taxonomyId}/terms/newparent/${newParentTerm}?${query}`) axios.tainacanApi.put(`/taxonomy/${taxonomyId}/terms/newparent/${newParentTerm}?${query}`)
.then(res => { .then(res => {
const terms = res.data; const terms = res.data;
resolve( terms ); resolve( terms );

View File

@ -976,7 +976,7 @@ export default {
} }
&:not(.available-metadata-area){ &:not(.available-metadata-area){
margin-right: var(--tainacan-one-column); margin-right: 30px;
flex-grow: 2; flex-grow: 2;
@media screen and (max-width: 769px) { @media screen and (max-width: 769px) {

View File

@ -33,7 +33,7 @@
id="filter-menu-compress-button" id="filter-menu-compress-button"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: !isFiltersModalActive ? $i18n.get('label_show_filters') : $i18n.get('label_hide_filters'), content: !isFiltersModalActive ? $i18n.get('label_show_filters') : $i18n.get('label_hide_filters'),
@ -223,16 +223,16 @@
ref="displayedMetadataDropdown" ref="displayedMetadataDropdown"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: (totalItems <= 0 || adminViewMode == 'grid'|| adminViewMode == 'cards' || adminViewMode == 'masonry') ? (adminViewMode == 'grid'|| adminViewMode == 'cards' || adminViewMode == 'masonry') ? $i18n.get('info_current_view_mode_metadata_not_allowed') : $i18n.get('info_cant_select_metadata_without_items') : '', content: (totalItems <= 0 || adminViewMode == 'grid'|| adminViewMode == 'cards' || adminViewMode == 'masonry' || adminViewMode == 'mosaic') ? (adminViewMode == 'grid'|| adminViewMode == 'cards' || adminViewMode == 'masonry' || adminViewMode == 'mosaic') ? $i18n.get('info_current_view_mode_metadata_not_allowed') : $i18n.get('info_cant_select_metadata_without_items') : '',
autoHide: false, autoHide: false,
placement: 'auto-start', placement: 'auto-start',
popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : ''] popperClass: ['tainacan-tooltip', 'tooltip', isRepositoryLevel ? 'tainacan-repository-tooltip' : '']
}" }"
:mobile-modal="true" :mobile-modal="true"
:disabled="totalItems <= 0 || adminViewMode == 'grid'|| adminViewMode == 'cards' || adminViewMode == 'masonry'" :disabled="totalItems <= 0 || adminViewMode == 'grid'|| adminViewMode == 'cards' || adminViewMode == 'masonry' || adminViewMode == 'mosaic'"
class="show metadata-options-dropdown" class="show metadata-options-dropdown"
aria-role="list" aria-role="list"
trap-focus> trap-focus>
@ -383,12 +383,15 @@
<span class="view-mode-icon icon is-small gray-icon"> <span class="view-mode-icon icon is-small gray-icon">
<i <i
v-if="adminViewMode !== 'map'" v-if="adminViewMode !== 'map'"
:class="{'tainacan-icon-viewtable' : ( adminViewMode == 'table' || adminViewMode == undefined), :class="{
'tainacan-icon-viewtable' : ( adminViewMode == 'table' || adminViewMode == undefined),
'tainacan-icon-viewcards' : adminViewMode == 'cards', 'tainacan-icon-viewcards' : adminViewMode == 'cards',
'tainacan-icon-viewminiature' : adminViewMode == 'grid', 'tainacan-icon-viewminiature' : adminViewMode == 'grid',
'tainacan-icon-viewrecords' : adminViewMode == 'records', 'tainacan-icon-viewrecords' : adminViewMode == 'records',
'tainacan-icon-viewlist' : adminViewMode == 'list', 'tainacan-icon-viewlist' : adminViewMode == 'list',
'tainacan-icon-viewmasonry' : adminViewMode == 'masonry' }" 'tainacan-icon-viewmasonry' : adminViewMode == 'masonry' || adminViewMode == 'mosaic',
'tainacan-icon-rotate-90' : adminViewMode == 'mosaic'
}"
class="tainacan-icon tainacan-icon-1-25em" /> class="tainacan-icon tainacan-icon-1-25em" />
<svg <svg
v-else v-else
@ -426,6 +429,17 @@
</span> </span>
<span>{{ $i18n.get('label_cards') }}</span> <span>{{ $i18n.get('label_cards') }}</span>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item
aria-controls="items-list-results"
role="button"
:class="{ 'is-active': adminViewMode == 'mosaic' }"
:value="'mosaic'"
aria-role="listitem">
<span class="icon gray-icon">
<i class="tainacan-icon tainacan-icon-viewmasonry tainacan-icon-rotate-90" />
</span>
<span>{{ $i18n.get('label_mosaic') }}</span>
</b-dropdown-item>
<b-dropdown-item <b-dropdown-item
v-if="!collection || (collection && collection.hide_items_thumbnail_on_lists != 'yes')" v-if="!collection || (collection && collection.hide_items_thumbnail_on_lists != 'yes')"
aria-controls="items-list-results" aria-controls="items-list-results"
@ -773,7 +787,7 @@
}, },
adminViewMode() { adminViewMode() {
const currentAdminViewMode = this.getAdminViewMode(); const currentAdminViewMode = this.getAdminViewMode();
return ['table', 'cards', 'records', 'grid', 'masonry', 'list', 'map'].indexOf(currentAdminViewMode) >= 0 ? currentAdminViewMode : 'table'; return ['table', 'cards', 'records', 'grid', 'masonry', 'list', 'map', 'mosaic'].indexOf(currentAdminViewMode) >= 0 ? currentAdminViewMode : 'table';
}, },
orderByName() { orderByName() {
const metadatumName = this.$orderByHelper.getOrderByMetadatumName({ const metadatumName = this.$orderByHelper.getOrderByMetadatumName({
@ -994,6 +1008,7 @@
existingViewMode == 'list' || existingViewMode == 'list' ||
existingViewMode == 'grid' || existingViewMode == 'grid' ||
existingViewMode == 'masonry'|| existingViewMode == 'masonry'||
existingViewMode == 'mosaic'||
existingViewMode == 'map') existingViewMode == 'map')
this.$eventBusSearch.setInitialAdminViewMode(this.$userPrefs.get(prefsAdminViewMode)); this.$eventBusSearch.setInitialAdminViewMode(this.$userPrefs.get(prefsAdminViewMode));
else else

View File

@ -74,6 +74,9 @@
// Filter Menu Width when not a modal // Filter Menu Width when not a modal
--tainacan-filter-menu-width-theme: #{$filter-menu-width-theme}; --tainacan-filter-menu-width-theme: #{$filter-menu-width-theme};
// Each filter width when in horizontal panel
--tainacan-filters-inline-width: #{$filters-inline-width};
// One column is 1/24% and it is used a lot in the horizontal space distribution // One column is 1/24% and it is used a lot in the horizontal space distribution
--tainacan-one-column: #{$one-column}; --tainacan-one-column: #{$one-column};

View File

@ -36,9 +36,15 @@
} }
} }
&.horizontal-filters {
.modal-content {
padding: calc(var(--tainacan-container-padding) - 12px) var(--tainacan-one-column) var(--tainacan-container-padding) var(--tainacan-one-column);
}
}
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
&:not(.filters-menu-modal) { &.modal:not(.filters-menu-modal) {
.modal-content { .modal-content {
background-color: var(--tainacan-background-color); background-color: var(--tainacan-background-color);
margin: 0 12% 0 0; margin: 0 12% 0 0;

View File

@ -316,7 +316,8 @@
.help-tooltip-header { .help-tooltip-header {
padding: 0.8em 0.8em 0em 0.8em; padding: 0.8em 0.8em 0em 0.8em;
h5 { h5,
p {
font-size: 0.875em !important; font-size: 0.875em !important;
font-weight: bold; font-weight: bold;
color: var(--tainacan-blue5); color: var(--tainacan-blue5);
@ -335,7 +336,7 @@
overflow: visible !important; overflow: visible !important;
max-height: 100% !important; max-height: 100% !important;
line-height: normal; line-height: normal;
color: var(--tainacan-blue5); color: var(--tainacan-info-color);
} }
} }
} }

View File

@ -145,6 +145,7 @@ $sidebar-width: 3.0em;
$subheader-height: 2.35em; $subheader-height: 2.35em;
$filter-menu-width: 16.666666667%; $filter-menu-width: 16.666666667%;
$filter-menu-width-theme: 20%; $filter-menu-width-theme: 20%;
$filters-inline-width: 272px;
$page-height: calc(100vh - 5.35em); $page-height: calc(100vh - 5.35em);
// Overall Pages padding: // Overall Pages padding:

View File

@ -140,7 +140,7 @@
.metadata-title { .metadata-title {
flex-shrink: 0; flex-shrink: 0;
padding: 0.6em 7em 0.5em 2.75em; padding: 0.6em 7em 0.5em 2.75em;
min-height: 40px; min-height: 1.5em;
position: relative; position: relative;
font-size: 1em !important; font-size: 1em !important;
text-overflow: ellipsis; text-overflow: ellipsis;
@ -187,6 +187,11 @@
display: flex; display: flex;
margin: 0 !important; margin: 0 !important;
&:hover,
&:focus {
background: var(--tainacan-item-hover-background-color);
}
.list-metadata { .list-metadata {
padding: 0.75em 1.375em; padding: 0.75em 1.375em;
flex: 1; flex: 1;

View File

@ -27,6 +27,7 @@
:deep(img) { :deep(img) {
height: auto; height: auto;
max-width: 100%;
} }
&:hover { &:hover {
@ -111,7 +112,7 @@
.metadata-title { .metadata-title {
flex-shrink: 0; flex-shrink: 0;
padding: 0.5em 7em 0.5em 2.75em; padding: 0.5em 7em 0.5em 2.75em;
min-height: 40px; min-height: 1.5em;
position: relative; position: relative;
font-size: 1em !important; font-size: 1em !important;
text-overflow: ellipsis; text-overflow: ellipsis;

View File

@ -264,6 +264,7 @@
z-index: 1; z-index: 1;
} }
.metadata-title { .metadata-title {
box-sizing: border-box;
flex-shrink: 0; flex-shrink: 0;
padding: 0.25em 1.125em; padding: 0.25em 1.125em;
font-size: 1.0em !important; font-size: 1.0em !important;

View File

@ -110,6 +110,7 @@
:deep(img) { :deep(img) {
height: auto; height: auto;
max-width: 100%;
} }
&:hover:not(.skeleton) { &:hover:not(.skeleton) {
@ -191,7 +192,7 @@
flex-shrink: 0; flex-shrink: 0;
margin: 0px 6px 0px 24px; margin: 0px 6px 0px 24px;
padding: 8px 1em; padding: 8px 1em;
min-height: 41px; min-height: calc(1em + 8px);
cursor: pointer; cursor: pointer;
position: relative; position: relative;

View File

@ -0,0 +1,223 @@
.tainacan-mosaic-container,
.tainacan-mosaic-container--skeleton {
--tainacan-mosaic-view-mode-gap: 12px;
--tainacan-mosaic-view-mode-min-height: 180px;
display: flex;
flex-wrap: wrap;
grid-gap: calc(2em + 18px) var(--tainacan-mosaic-view-mode-gap, 12px);
list-style: none;
height: auto;
min-height: 0px; /* While most view modes set this to 50vh, this causes a bug for this one if there are few items to display */
margin: 0;
margin-bottom: calc(2em + 18px + var(--tainacan-container-padding));
padding: 0;
list-style: none;
animation-name: appear;
animation-duration: 0.5s;
&::after {
content: " ";
flex-grow: 1000000000;
}
& > li,
& > .skeleton {
flex-grow: calc(var(--tainacan-mosaic-item-width, 300) * (100000 / var(--tainacan-mosaic-item-height, 300)));
flex-basis: calc(var(--tainacan-mosaic-view-mode-min-height, 180) * (var(--tainacan-mosaic-item-width, 300) / var(--tainacan-mosaic-item-height, 300)));
aspect-ratio: var(--tainacan-mosaic-item-width, 300) / var(--tainacan-mosaic-item-height, 300);
position: relative;
margin: 0 !important;
padding: 0 !important;
:deep(img) {
position: absolute;
width: auto;
height: 100%;
}
:deep(canvas.child) {
aspect-ratio: var(--tainacan-mosaic-item-width, 300) / var(--tainacan-mosaic-item-height, 300);
}
&:hover:not(.skeleton) {
background-color: var(--tainacan-item-heading-hover-background-color);
}
&.selected-mosaic-item:not(.skeleton) {
background-color: var(--tainacan-turquoise1);
}
&:not(.skeleton) {
background-color: var(--tainacan-item-background-color);
}
.tainacan-mosaic-item {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.mosaic-item-checkbox {
position: absolute;
margin-top: -2px;
margin-left: -1em;
z-index: 9;
}
.actions-area {
position: relative;
float: right;
width: 100%;
height: 0px;
display: flex;
justify-content: flex-end;
visibility: hidden;
overflow: hidden;
opacity: 0.0;
padding: 8px;
margin-top: -25px;
background-color: var(--tainacan-item-heading-hover-background-color);
transition: visibility 0.2s ease, opacity 0.3s ease, height 0.2s ease, margin-top 0.1s ease;
a {
margin-left: 8px;
opacity: 0;
transition: opacity 0.3s ease-in;
}
}
&:hover,
&:focus,
&:focus-within,
&:focus-visible,
& > a:focus,
& > a:focus-within,
& > a:focus-visible {
background: var(--tainacan-item-hover-background-color);
.actions-area {
visibility: visible;
opacity: 1.0;
height: 42px;
margin-top: 0px;
background-color: var(--tainacan-item-heading-hover-background-color);
a {
opacity: 1;
}
}
}
& > .selected-mosaic-item {
background-color: var(--tainacan-turquoise1);
.actions-area,
.metadata-title {
background-color: var(--tainacan-turquoise1) !important;
}
}
.tainacan-mosaic-item-thumbnail {
background-size: cover;
background-color: var(--tainacan-item-background-color);
background-blend-mode: multiply;
border-radius: 0px;
min-width: 100%;
display: flex;
justify-content: center;
&:hover {
cursor: pointer;
}
}
.metadata-title {
display: flex;
align-items: center;
justify-content: space-between;
flex-shrink: 0;
margin: 0;
padding: 8px 1em;
min-height: calc(1em + 8px);
width: 100%;
cursor: pointer;
position: absolute;
top: 100%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
p {
font-size: 0.875em !important;
color: var(--tainacan-heading-color) !important;
text-align: left !important;
margin-bottom: 0 !important;
line-height: 1.5em;
word-break: break-word;
margin: 0;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.slideshow-icon {
color: var(--tainacan-info-color);
position: absolute;
right: 5px;
top: 8px;
transform: scale(0.0);
transition: transform 0.2s ease;
}
.icon:not(.slideshow-icon) {
float: left;
margin-top: -1px;
}
}
&:hover,
&:focus,
&:focus-within,
&:focus-visible,
& > a:focus,
& > a:focus-within,
& > a:focus-visible {
.metadata-title {
background: var(--tainacan-item-heading-hover-background-color);
.slideshow-icon {
transform: scale(1.0);
}
}
}
}
&.hide-items-selection {
.tainacan-mosaic-item {
&:hover { background-color: transparent; cursor: default; }
&:hover .tainacan-mosaic-item-thumbnail { cursor: default; }
}
}
&.has-title-inside {
gap: var(--tainacan-mosaic-view-mode-gap, 12px);
& > li {
.metadata-title {
top: unset;
bottom: 0;
white-space: wrap;
overflow: visible;
text-overflow: none;
p {
white-space: wrap;
overflow: visible;
text-overflow: none;
}
}
&:not(:hover):not(:focus):not(:focus-within):not(:focus-visible),
& > a:not(:hover):not(:focus):not(:focus-within):not(:focus-visible) {
.metadata-title {
display: none;
}
}
}
}
}

View File

@ -75,6 +75,7 @@
:deep(img) { :deep(img) {
height: auto; height: auto;
max-width: 100%;
} }
&:hover { &:hover {
@ -150,7 +151,7 @@
flex-shrink: 0; flex-shrink: 0;
padding: 0.5em 7em 0.5em 2.75em; padding: 0.5em 7em 0.5em 2.75em;
font-size: 1.0em !important; font-size: 1.0em !important;
min-height: 40px; min-height: 1.5em;
position: relative; position: relative;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;

View File

@ -354,7 +354,8 @@ class Admin {
'wp_elasticpress' => \Tainacan\Elastic_Press::get_instance()->is_active(), 'wp_elasticpress' => \Tainacan\Elastic_Press::get_instance()->is_active(),
'item_submission_captcha_site_key' => get_option("tnc_option_recaptch_site_key"), 'item_submission_captcha_site_key' => get_option("tnc_option_recaptch_site_key"),
'tainacan_enable_core_metadata_on_advanced_search' => ( !defined('TAINACAN_DISABLE_CORE_METADATA_ON_ADVANCED_SEARCH') || false === TAINACAN_DISABLE_CORE_METADATA_ON_ADVANCED_SEARCH ), 'tainacan_enable_core_metadata_on_advanced_search' => ( !defined('TAINACAN_DISABLE_CORE_METADATA_ON_ADVANCED_SEARCH') || false === TAINACAN_DISABLE_CORE_METADATA_ON_ADVANCED_SEARCH ),
'tainacan_enable_relationship_metaquery' => ( defined('TAINACAN_ENABLE_RELATIONSHIP_METAQUERY') && true === TAINACAN_ENABLE_RELATIONSHIP_METAQUERY ) 'tainacan_enable_relationship_metaquery' => ( defined('TAINACAN_ENABLE_RELATIONSHIP_METAQUERY') && true === TAINACAN_ENABLE_RELATIONSHIP_METAQUERY ),
'has_permalinks_structure' => get_option('permalink_structure') !== ''
]; ];
$maps = [ $maps = [

View File

@ -28,7 +28,7 @@ export default (element) => {
let registeredViewModes = let registeredViewModes =
( tainacan_blocks && tainacan_blocks.registered_view_modes && tainacan_blocks.registered_view_modes.length ) ? ( tainacan_blocks && tainacan_blocks.registered_view_modes && tainacan_blocks.registered_view_modes.length ) ?
tainacan_blocks.registered_view_modes : tainacan_blocks.registered_view_modes :
[ 'table', 'cards', 'records', 'masonry', 'list', 'map' ]; [ 'table', 'cards', 'records', 'masonry', 'mosaic', 'list', 'map'];
// At first, we consider that all registered view modes are included. // At first, we consider that all registered view modes are included.
let possibleViewModes = registeredViewModes.filter((aViewMode) => aViewMode === 'slideshow'); let possibleViewModes = registeredViewModes.filter((aViewMode) => aViewMode === 'slideshow');

View File

@ -212,6 +212,22 @@
"collectionOrderByType": { "collectionOrderByType": {
"type": "string", "type": "string",
"default": "" "default": ""
},
"shouldNotHideFiltersOnMobile": {
"type": "boolean",
"default": false
},
"displayFiltersHorizontally": {
"type": "boolean",
"default": false
},
"hideFilterCollapses": {
"type": "boolean",
"default": false
},
"filtersInlineWidth": {
"type": "number",
"default": 272
} }
}, },
"supports": { "supports": {

View File

@ -1,6 +1,327 @@
const { useBlockProps } = wp.blockEditor; const { useBlockProps } = wp.blockEditor;
export default [ export default [
/* Deprecated due to the creation of horizontal questions */
{
"attributes": {
"termId": {
"type": "string",
"default": null
},
"taxonomyId": {
"type": "string",
"default": null
},
"collectionId": {
"type": "string",
"default": null
},
"defaultViewMode": {
"type": "string",
"default": "masonry"
},
"enabledViewModes": {
"type": "array",
"default": []
},
"collectionDefaultViewMode": {
"type": "string",
"default": "masonry"
},
"collectionEnabledViewModes": {
"type": "array",
"default": []
},
"hideFilters": {
"type": "boolean",
"default": false
},
"hideHideFiltersButton": {
"type": "boolean",
"default": false
},
"hideSearch": {
"type": "boolean",
"default": false
},
"hideAdvancedSearch": {
"type": "boolean",
"default": false
},
"hideDisplayedMetadataButton": {
"type": "boolean",
"default": false
},
"hideSortingArea": {
"type": "boolean",
"default": false
},
"hideSortByButton": {
"type": "boolean",
"default": false
},
"hideItemsThumbnail": {
"type": "boolean",
"default": false
},
"hideExposersButton": {
"type": "boolean",
"default": false
},
"hideItemsPerPageButton": {
"type": "boolean",
"default": false
},
"defaultItemsPerPage": {
"type": "number",
"default": 12
},
"hideGoToPageButton": {
"type": "boolean",
"default": false
},
"hidePaginationArea": {
"type": "boolean",
"default": false
},
"showFiltersButtonInsideSearchControl": {
"type": "boolean",
"default": false
},
"startWithFiltersHidden": {
"type": "boolean",
"default": false
},
"filtersAsModal": {
"type": "boolean",
"default": false
},
"showInlineViewModeOptions": {
"type": "boolean",
"default": false
},
"showFullscreenWithViewModes": {
"type": "boolean",
"default": false
},
"listType": {
"type": "string",
"default": ""
},
"isCollectionModalOpen": {
"type": "boolean",
"default": false
},
"isTermModalOpen": {
"type": "boolean",
"default": false
},
"backgroundColor": {
"type": "string",
"default": "#ffffff"
},
"baseFontSize": {
"type": "number",
"default": 16
},
"filtersAreaWidth": {
"type": "number",
"default": 20
},
"inputColor": {
"type": "string",
"default": "#1d1d1d"
},
"inputBackgroundColor": {
"type": "string",
"default": "#ffffff"
},
"inputBorderColor": {
"type": "string",
"default": "#dbdbdb"
},
"labelColor": {
"type": "string",
"default": "#373839"
},
"infoColor": {
"type": "string",
"default": "#505253"
},
"headingColor": {
"type": "string",
"default": "#000000"
},
"skeletonColor": {
"type": "string",
"default": "#eeeeee"
},
"itemBackgroundColor": {
"type": "string",
"default": "#ffffff"
},
"itemHoverBackgroundColor": {
"type": "string",
"default": "#f2f2f2"
},
"itemHeadingHoverBackgroundColor": {
"type": "string",
"default": "#dbdbdb"
},
"primaryColor": {
"type": "string",
"default": "#d9eced"
},
"secondaryColor": {
"type": "string",
"default": "#187181"
},
"order": {
"type": "string",
"default": "ASC"
},
"orderBy": {
"type": "string",
"default": "date"
},
"orderByMeta": {
"type": "string",
"default": ""
},
"orderByType": {
"type": "string",
"default": ""
},
"collectionOrderBy": {
"type": "string",
"default": "date"
},
"collectionOrderByMeta": {
"type": "string",
"default": ""
},
"collectionOrderByType": {
"type": "string",
"default": ""
}
},
save: function({ attributes }) {
const {
termId,
taxonomyId,
collectionId,
defaultViewMode,
enabledViewModes,
collectionDefaultViewMode,
collectionEnabledViewModes,
hideDisplayedMetadataButton,
hideSortingArea,
hideFilters,
hideHideFiltersButton,
hideSearch,
hideAdvancedSearch,
hideSortByButton,
hideItemsThumbnail,
hidePaginationArea,
hideExposersButton,
hideItemsPerPageButton,
defaultItemsPerPage,
hideGoToPageButton,
showFiltersButtonInsideSearchControl,
startWithFiltersHidden,
filtersAsModal,
showInlineViewModeOptions,
showFullscreenWithViewModes,
listType,
backgroundColor,
baseFontSize,
filtersAreaWidth,
inputColor,
inputBackgroundColor,
inputBorderColor,
labelColor,
infoColor,
headingColor,
skeletonColor,
itemBackgroundColor,
itemHoverBackgroundColor,
itemHeadingHoverBackgroundColor,
primaryColor,
secondaryColor,
order,
orderBy,
orderByMeta,
orderByType,
collectionOrderBy,
collectionOrderByMeta,
collectionOrderByType
} = attributes;
let updatedListType = '' + listType;
if (updatedListType === '' && collectionId)
updatedListType = 'collection';
else if (updatedListType === '' && termId && taxonomyId)
updatedListType = 'term';
// Gets attributes such as style, that are automatically added by the editor hook
const blockProps = useBlockProps.save();
return <div
style={{
'font-size': baseFontSize + 'px',
'--tainacan-base-font-size': baseFontSize + 'px',
'--tainacan-background-color': backgroundColor,
'--tainacan-filter-menu-width-theme': filtersAreaWidth + '%',
'--tainacan-input-color': inputColor,
'--tainacan-input-background-color': inputBackgroundColor,
'--tainacan-input-border-color': inputBorderColor,
'--tainacan-label-color': labelColor,
'--tainacan-info-color': infoColor,
'--tainacan-heading-color': headingColor,
'--tainacan-skeleton-color': skeletonColor,
'--tainacan-item-background-color': itemBackgroundColor,
'--tainacan-item-hover-background-color': itemHoverBackgroundColor,
'--tainacan-item-heading-hover-background-color': itemHeadingHoverBackgroundColor,
'--tainacan-primary': primaryColor,
'--tainacan-secondary': secondaryColor
}}
{ ...blockProps }>
<main
id="tainacan-items-page"
data-module="faceted-search"
data-term-id={ updatedListType == 'term' ? termId : null }
data-taxonomy={ updatedListType == 'term' ? 'tnc_tax_' + taxonomyId : null }
data-collection-id={ updatedListType == 'collection' ? collectionId : null }
data-default-view-mode={ defaultViewMode != 'none' ? defaultViewMode : (updatedListType == 'collection' ? collectionDefaultViewMode : (hideItemsThumbnail ? 'table' : 'masonry') ) }
data-is-forced-view-mode={ defaultViewMode == 'none' ? 'true' : 'false' }
data-enabled-view-modes={ enabledViewModes ? enabledViewModes.toString() : '' }
data-hide-filters = { hideFilters.toString() }
data-hide-hide-filters-button= { hideHideFiltersButton.toString() }
data-hide-search = { hideSearch.toString() }
data-hide-advanced-search = { hideAdvancedSearch.toString() }
data-hide-displayed-metadata-button = { hideDisplayedMetadataButton.toString() }
data-hide-pagination-area = { hidePaginationArea.toString() }
data-hide-sorting-area = { hideSortingArea.toString() }
data-hide-items-thumbnail = { hideItemsThumbnail ? hideItemsThumbnail.toString() : 'false' }
data-hide-sort-by-button = { hideSortByButton.toString() }
data-hide-exposers-button = { hideExposersButton.toString() }
data-hide-items-per-page-button = { hideItemsPerPageButton.toString() }
data-default-items-per-page = { defaultItemsPerPage }
data-hide-go-to-page-button = { hideGoToPageButton.toString() }
data-show-filters-button-inside-search-control = { showFiltersButtonInsideSearchControl.toString() }
data-start-with-filters-hidden = { startWithFiltersHidden.toString() }
data-filters-as-modal = { filtersAsModal.toString() }
data-show-inline-view-mode-options = { showInlineViewModeOptions.toString() }
data-show-fullscreen-with-view-modes = { showFullscreenWithViewModes.toString() }
data-default-order = { order ? order : 'ASC' }
data-default-orderby = { updatedListType == 'collection' ? (collectionOrderBy ? collectionOrderBy : 'date') : (orderBy ? orderBy : 'date') }
data-default-orderby-meta = { updatedListType == 'collection' ? (collectionOrderByMeta ? collectionOrderByMeta : '') : (orderByMeta ? orderByMeta : '') }
data-default-orderby-type = { updatedListType == 'collection' ? (collectionOrderByType ? collectionOrderByType : '') : (orderByType ? orderByType : '') } >
</main>
</div>
}
},
/* Deprecated during Vue 3 migration to prepend attributes with data- */ /* Deprecated during Vue 3 migration to prepend attributes with data- */
{ {
"attributes": { "attributes": {

View File

@ -76,7 +76,11 @@ export default function({ attributes, setAttributes, isSelected, clientId }) {
orderByType, orderByType,
collectionOrderBy, collectionOrderBy,
collectionOrderByMeta, collectionOrderByMeta,
collectionOrderByType collectionOrderByType,
shouldNotHideFiltersOnMobile,
displayFiltersHorizontally,
hideFilterCollapses,
filtersInlineWidth
} = attributes; } = attributes;
// Gets blocks props from hook // Gets blocks props from hook
@ -89,7 +93,7 @@ export default function({ attributes, setAttributes, isSelected, clientId }) {
if ( enabledViewModes === null || !enabledViewModes.length ) if ( enabledViewModes === null || !enabledViewModes.length )
enabledViewModes = Object.keys(tainacan_plugin.registered_view_modes); enabledViewModes = Object.keys(tainacan_plugin.registered_view_modes);
console.log('edit', collectionOrderByMeta);
const fontSizes = [ const fontSizes = [
{ {
name: __( 'Tiny', 'tainacan' ), name: __( 'Tiny', 'tainacan' ),
@ -497,6 +501,16 @@ export default function({ attributes, setAttributes, isSelected, clientId }) {
setAttributes({ startWithFiltersHidden: isChecked }); setAttributes({ startWithFiltersHidden: isChecked });
} }
} }
/>
<ToggleControl
label={__('Should not hide filters even on mobile', 'tainacan')}
help={ shouldNotHideFiltersOnMobile || shouldNotHideFiltersOnMobile === undefined ? __('Toggle to keep filters area visible even on small screen sizes.', 'tainacan') : __('Automatically hide filters area on small screen sizes inside a modal', 'tainacan') }
checked={ shouldNotHideFiltersOnMobile && !filtersAsModal }
onChange={ ( isChecked ) => {
shouldNotHideFiltersOnMobile = isChecked;
setAttributes({ shouldNotHideFiltersOnMobile: isChecked });
}
}
/> />
<ToggleControl <ToggleControl
label={__('Filters as a Modal', 'tainacan')} label={__('Filters as a Modal', 'tainacan')}
@ -508,6 +522,26 @@ export default function({ attributes, setAttributes, isSelected, clientId }) {
} }
} }
/> />
<ToggleControl
label={ __('Display filters horizontally', 'tainacan') }
help={ displayFiltersHorizontally ? __( 'Toggle to not show filters in an horizontal pane above the search control.', 'tainacan') : __( 'Toggle to show filters in an horizontal pane above the search control instead of a vertical sidebar. This layout fits better with select and textual input filters.', 'tainacan') }
checked={ displayFiltersHorizontally }
onChange={ ( isChecked ) => {
displayFiltersHorizontally = isChecked;
setAttributes({ displayFiltersHorizontally: isChecked });
}
}
/>
<ToggleControl
label={ __('Hide filter collapses button', 'tainacan') }
help={ __('Toggle to not display each filter label as a collapsable button. This is suggested when you have a small amount of filters.', 'tainacan') }
checked={ hideFilterCollapses }
onChange={ ( isChecked ) => {
hideFilterCollapses = isChecked;
setAttributes({ hideFilterCollapses: isChecked });
}
}
/>
</PanelBody> </PanelBody>
<PanelBody <PanelBody
@ -569,6 +603,7 @@ export default function({ attributes, setAttributes, isSelected, clientId }) {
setAttributes( { baseFontSize: newFontSize } ); setAttributes( { baseFontSize: newFontSize } );
} } } }
/> />
{ !displayFiltersHorizontally && !filtersAsModal ?
<RangeControl <RangeControl
label={ __('Filters Area Width (%)', 'tainacan') } label={ __('Filters Area Width (%)', 'tainacan') }
value={ filtersAreaWidth } value={ filtersAreaWidth }
@ -576,6 +611,16 @@ export default function({ attributes, setAttributes, isSelected, clientId }) {
min={ 10 } min={ 10 }
max={ 40 } max={ 40 }
/> />
: null }
{ displayFiltersHorizontally ?
<RangeControl
label={ __('Filters Inline Width (px)', 'tainacan') }
value={ filtersInlineWidth }
onChange={ ( width ) => setAttributes( { filtersInlineWidth: width } ) }
min={ 100 }
max={ 800 }
/>
: null }
</PanelBody> </PanelBody>
<PanelBody <PanelBody
title={__('Colors', 'tainacan')} title={__('Colors', 'tainacan')}
@ -815,6 +860,7 @@ export default function({ attributes, setAttributes, isSelected, clientId }) {
style={{ style={{
'--tainacan-background-color': backgroundColor, '--tainacan-background-color': backgroundColor,
'--tainacan-filter-menu-width-theme': filtersAreaWidth + '%', '--tainacan-filter-menu-width-theme': filtersAreaWidth + '%',
'--tainacan-filters-inline-width': filtersInlineWidth + 'px',
'--tainacan-input-color': inputColor, '--tainacan-input-color': inputColor,
'--tainacan-input-background-color': inputBackgroundColor, '--tainacan-input-background-color': inputBackgroundColor,
'--tainacan-input-border-color': inputBorderColor, '--tainacan-input-border-color': inputBorderColor,
@ -866,7 +912,7 @@ export default function({ attributes, setAttributes, isSelected, clientId }) {
!hideExposersButton ? <span className="fake-button"><div className="fake-icon"></div><div className="fake-text"></div></span> : null !hideExposersButton ? <span className="fake-button"><div className="fake-icon"></div><div className="fake-text"></div></span> : null
} }
</div> </div>
<div className="below-search-control"> <div className={ 'below-search-control' + (displayFiltersHorizontally ? ' horizontal-filters' : '') }>
{ !showFiltersButtonInsideSearchControl & !hideHideFiltersButton && !hideFilters ? <span className="fake-hide-button"><div className="fake-icon"></div></span> : null } { !showFiltersButtonInsideSearchControl & !hideHideFiltersButton && !hideFilters ? <span className="fake-hide-button"><div className="fake-icon"></div></span> : null }
{ {
!hideFilters && !filtersAsModal && !startWithFiltersHidden ? !hideFilters && !filtersAsModal && !startWithFiltersHidden ?
@ -876,6 +922,7 @@ export default function({ attributes, setAttributes, isSelected, clientId }) {
}} }}
className="filters"> className="filters">
<div className="fake-filters-heading"></div> <div className="fake-filters-heading"></div>
{ !hideFilterCollapses ? <span className="fake-link"></span> : null }
{ Array(2).fill().map( () => { { Array(2).fill().map( () => {
return <div className="fake-filter"> return <div className="fake-filter">
<span className="fake-text"></span> <span className="fake-text"></span>

View File

@ -49,7 +49,11 @@ export default function({ attributes }) {
orderByType, orderByType,
collectionOrderBy, collectionOrderBy,
collectionOrderByMeta, collectionOrderByMeta,
collectionOrderByType collectionOrderByType,
shouldNotHideFiltersOnMobile,
displayFiltersHorizontally,
hideFilterCollapses,
filtersInlineWidth
} = attributes; } = attributes;
let updatedListType = '' + listType; let updatedListType = '' + listType;
@ -58,7 +62,7 @@ export default function({ attributes }) {
updatedListType = 'collection'; updatedListType = 'collection';
else if (updatedListType === '' && termId && taxonomyId) else if (updatedListType === '' && termId && taxonomyId)
updatedListType = 'term'; updatedListType = 'term';
console.log('save', updatedListType, collectionOrderByMeta)
// Gets attributes such as style, that are automatically added by the editor hook // Gets attributes such as style, that are automatically added by the editor hook
const blockProps = useBlockProps.save(); const blockProps = useBlockProps.save();
@ -68,6 +72,7 @@ export default function({ attributes }) {
'--tainacan-base-font-size': baseFontSize + 'px', '--tainacan-base-font-size': baseFontSize + 'px',
'--tainacan-background-color': backgroundColor, '--tainacan-background-color': backgroundColor,
'--tainacan-filter-menu-width-theme': filtersAreaWidth + '%', '--tainacan-filter-menu-width-theme': filtersAreaWidth + '%',
'--tainacan-filters-inline-width': filtersInlineWidth + 'px',
'--tainacan-input-color': inputColor, '--tainacan-input-color': inputColor,
'--tainacan-input-background-color': inputBackgroundColor, '--tainacan-input-background-color': inputBackgroundColor,
'--tainacan-input-border-color': inputBorderColor, '--tainacan-input-border-color': inputBorderColor,
@ -112,7 +117,10 @@ export default function({ attributes }) {
data-default-order = { order ? order : 'ASC' } data-default-order = { order ? order : 'ASC' }
data-default-orderby = { updatedListType == 'collection' ? (collectionOrderBy ? collectionOrderBy : 'date') : (orderBy ? orderBy : 'date') } data-default-orderby = { updatedListType == 'collection' ? (collectionOrderBy ? collectionOrderBy : 'date') : (orderBy ? orderBy : 'date') }
data-default-orderby-meta = { updatedListType == 'collection' ? (collectionOrderByMeta ? collectionOrderByMeta : '') : (orderByMeta ? orderByMeta : '') } data-default-orderby-meta = { updatedListType == 'collection' ? (collectionOrderByMeta ? collectionOrderByMeta : '') : (orderByMeta ? orderByMeta : '') }
data-default-orderby-type = { updatedListType == 'collection' ? (collectionOrderByType ? collectionOrderByType : '') : (orderByType ? orderByType : '') } > data-default-orderby-type = { updatedListType == 'collection' ? (collectionOrderByType ? collectionOrderByType : '') : (orderByType ? orderByType : '') }
data-should-not-hide-filters-on-mobile = { shouldNotHideFiltersOnMobile ? shouldNotHideFiltersOnMobile.toString() : 'false' }
data-hide-filter-collapses = { hideFilterCollapses ? hideFilterCollapses.toString() : 'false' }
data-display-filters-horizontally = { displayFiltersHorizontally ? displayFiltersHorizontally.toString() : 'false' } >
</main> </main>
</div> </div>
}; };

View File

@ -56,6 +56,33 @@
flex-direction: row; flex-direction: row;
flex: 1 0 auto; flex: 1 0 auto;
&.horizontal-filters {
flex-direction: column;
.filters {
flex-direction: row;
flex: 0 1 100%;
flex-wrap: wrap;
padding: 18px 12px 6px 12px;
.fake-filters-heading {
margin-right: 90%;
top: -0.5em;
left: 0.5em;
}
.fake-filters-heading + .fake-link {
margin-right: 95%;
margin-left: 12px;
}
.fake-filter {
margin: 6px 12px;
display: inline-flex;
width: var(--tainacan-filters-inline-width, 272px);
}
}
}
.filters { .filters {
flex: 0 1 var(--tainacan-filter-menu-width-theme, 20%); flex: 0 1 var(--tainacan-filter-menu-width-theme, 20%);
display: flex; display: flex;
@ -66,7 +93,8 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 80%; width: 80%;
margin: 5% 12%; margin: 5% 8%;
.fake-text { .fake-text {
margin: 4px 0; margin: 4px 0;
width: 35%; width: 35%;

View File

@ -43,7 +43,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined ? item.title : '', content: item.title != undefined ? item.title : '',
@ -57,7 +57,7 @@
v-if="isSlideshowViewModeEnabled" v-if="isSlideshowViewModeEnabled"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 100, hide: 100,
}, },
content: $i18n.get('label_see_on_fullscreen'), content: $i18n.get('label_see_on_fullscreen'),
@ -92,7 +92,7 @@
<p <p
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined ? item.title : '', content: item.title != undefined ? item.title : '',

View File

@ -43,7 +43,7 @@
v-if="collectionId && titleItemMetadatum" v-if="collectionId && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.metadata != undefined ? renderMetadata(item, titleItemMetadatum) : '', content: item.metadata != undefined ? renderMetadata(item, titleItemMetadatum) : '',
@ -57,7 +57,7 @@
v-if="!collectionId && titleItemMetadatum" v-if="!collectionId && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`), content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`),
@ -71,7 +71,7 @@
v-if="isSlideshowViewModeEnabled" v-if="isSlideshowViewModeEnabled"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 100, hide: 100,
}, },
content: $i18n.get('label_see_on_fullscreen'), content: $i18n.get('label_see_on_fullscreen'),

View File

@ -43,7 +43,7 @@
v-if="collectionId && titleItemMetadatum" v-if="collectionId && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.metadata != undefined ? renderMetadata(item, titleItemMetadatum) : '', content: item.metadata != undefined ? renderMetadata(item, titleItemMetadatum) : '',
@ -57,7 +57,7 @@
v-if="!collectionId && titleItemMetadatum" v-if="!collectionId && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`), content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`),
@ -84,7 +84,7 @@
v-if="isSlideshowViewModeEnabled" v-if="isSlideshowViewModeEnabled"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 100, hide: 100,
}, },
content: $i18n.get('label_see_on_fullscreen'), content: $i18n.get('label_see_on_fullscreen'),
@ -273,7 +273,7 @@
v-if="collectionId && titleItemMetadatum" v-if="collectionId && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.metadata != undefined ? renderMetadata(item, titleItemMetadatum) : '', content: item.metadata != undefined ? renderMetadata(item, titleItemMetadatum) : '',
@ -287,7 +287,7 @@
v-if="!collectionId && titleItemMetadatum" v-if="!collectionId && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`), content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`),
@ -301,7 +301,7 @@
v-if="isSlideshowViewModeEnabled" v-if="isSlideshowViewModeEnabled"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 100, hide: 100,
}, },
content: $i18n.get('label_see_on_fullscreen'), content: $i18n.get('label_see_on_fullscreen'),

View File

@ -51,7 +51,7 @@
v-if="isSlideshowViewModeEnabled" v-if="isSlideshowViewModeEnabled"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 100, hide: 100,
}, },
content: $i18n.get('label_see_on_fullscreen'), content: $i18n.get('label_see_on_fullscreen'),

View File

@ -0,0 +1,137 @@
<template>
<div class="table-container">
<div class="table-wrapper">
<!-- Empty result placeholder, rendered in the parent component -->
<slot />
<!-- SKELETON LOADING -->
<div
v-if="isLoading"
class="tainacan-mosaic-container--skeleton">
<div
v-for="item in 12"
:key="item"
:style="{
'--tainacan-mosaic-item-width': randomHeightForMosaicItem(),
'--tainacan-mosaic-item-height': randomHeightForMosaicItem()
}"
class="skeleton" />
</div>
<!-- MOSAIC VIEW MODE -->
<ul
v-if="!isLoading"
class="tainacan-mosaic-container">
<li
v-for="(item, index) of items"
:key="index"
:style="{
'--tainacan-mosaic-item-width': getAcceptableWidthBasedOnRatio(item['thumbnail'], 'tainacan-large-full', 300),
'--tainacan-mosaic-item-height': $thumbHelper.getHeight(item['thumbnail'], 'tainacan-large-full', 300)
}"
:data-tainacan-item-id="item.id"
:aria-setsize="totalItems"
:aria-posinset="getPosInSet(index)">
<a
class="tainacan-mosaic-item"
:href="getItemLink(item.url, index)">
<!-- JS-side hook for extra content -->
<div
v-if="hasBeforeHook()"
class="faceted-search-hook faceted-search-hook-item-before"
v-html="getBeforeHook(item)" />
<!-- Thumbnail -->
<blur-hash-image
v-if="item.thumbnail != undefined"
class="tainacan-mosaic-item-thumbnail"
:width="$thumbHelper.getWidth(item['thumbnail'], 'tainacan-large-full', 320)"
:height="$thumbHelper.getHeight(item['thumbnail'], 'tainacan-large-full', 320)"
:hash="$thumbHelper.getBlurhashString(item['thumbnail'], 'tainacan-large-full')"
:src="$thumbHelper.getSrc(item['thumbnail'], 'tainacan-large-full', item.document_mimetype)"
:srcset="$thumbHelper.getSrcSet(item['thumbnail'], 'tainacan-large-full', item.document_mimetype)"
:alt="item.thumbnail_alt ? item.thumbnail_alt : $i18n.get('label_thumbnail')"
:transition-duration="500"
/>
<!-- Title -->
<div
class="metadata-title"
:style="isSlideshowViewModeEnabled ? 'padding-right: 2rem;' : ''">
<p
v-tooltip="{
delay: {
show: 750,
hide: 100,
},
content: item.title != undefined ? item.title : '',
html: true,
placement: 'auto-start',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
v-html="item.title != undefined ? item.title : ''" />
<span
v-if="isSlideshowViewModeEnabled"
v-tooltip="{
delay: {
show: 500,
hide: 100,
},
content: $i18n.get('label_see_on_fullscreen'),
placement: 'auto-start',
popperClass: ['tainacan-tooltip', 'tooltip']
}"
class="icon slideshow-icon"
@click.prevent="starSlideshowFromHere(index)">
<i class="tainacan-icon tainacan-icon-viewgallery tainacan-icon-1-125em" />
</span>
</div>
<!-- JS-side hook for extra content -->
<div
v-if="hasAfterHook()"
class="faceted-search-hook faceted-search-hook-item-after"
v-html="getAfterHook(item)" />
</a>
</li>
</ul>
</div>
</div>
</template>
<script>
import { viewModesMixin } from '../js/view-modes-mixin.js';
export default {
name: 'ViewModeMosaic',
mixins: [
viewModesMixin
],
methods: {
randomHeightForMosaicItem() {
let min = 120;
let max = 280;
return Math.floor(Math.random()*(max-min+1)+min);
},
getAcceptableWidthBasedOnRatio(thumbnail, size, defaultSize) {
const width = this.$thumbHelper.getWidth(thumbnail, size, defaultSize);
const height = this.$thumbHelper.getHeight(thumbnail, size, defaultSize);
return (width / height) > 0.7 ? width : ( height * 0.7 );
}
}
}
</script>
<style lang="scss" scoped>
@import "../../../../../admin/scss/_view-mode-mosaic.scss";
</style>

View File

@ -46,7 +46,7 @@
v-if="collectionId && titleItemMetadatum" v-if="collectionId && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.metadata != undefined ? renderMetadata(item, titleItemMetadatum) : '', content: item.metadata != undefined ? renderMetadata(item, titleItemMetadatum) : '',
@ -60,7 +60,7 @@
v-if="!collectionId && titleItemMetadatum" v-if="!collectionId && titleItemMetadatum"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`), content: item.title != undefined ? item.title : (`<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`),
@ -74,7 +74,7 @@
v-if="isSlideshowViewModeEnabled" v-if="isSlideshowViewModeEnabled"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 100, hide: 100,
}, },
content: $i18n.get('label_see_on_fullscreen'), content: $i18n.get('label_see_on_fullscreen'),

View File

@ -9,7 +9,7 @@
id="slides-help-button" id="slides-help-button"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_slides_help'), content: $i18n.get('label_slides_help'),
@ -29,7 +29,7 @@
id="metedata-panel-button" id="metedata-panel-button"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: isMetadataCompressed ? $i18n.get('label_show_metadata') : $i18n.get('label_hide_metadata'), content: isMetadataCompressed ? $i18n.get('label_show_metadata') : $i18n.get('label_hide_metadata'),
@ -50,7 +50,7 @@
id="item-page-button" id="item-page-button"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('label_item_page'), content: $i18n.get('label_item_page'),
@ -70,7 +70,7 @@
id="close-fullscren-button" id="close-fullscren-button"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: $i18n.get('close'), content: $i18n.get('close'),
@ -90,7 +90,7 @@
id="metadata-compress-button" id="metadata-compress-button"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: isMetadataCompressed ? $i18n.get('label_show_metadata') : $i18n.get('label_hide_metadata'), content: isMetadataCompressed ? $i18n.get('label_show_metadata') : $i18n.get('label_hide_metadata'),
@ -325,7 +325,7 @@
<span <span
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: metadatum.name, content: metadatum.name,

View File

@ -136,7 +136,7 @@
column.metadata_type_object.related_mapped_prop == 'title'" column.metadata_type_object.related_mapped_prop == 'title'"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.title != undefined && item.title != '' ? item.title : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`, content: item.title != undefined && item.title != '' ? item.title : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`,
@ -153,7 +153,7 @@
column.metadata_type_object.related_mapped_prop == 'description'" column.metadata_type_object.related_mapped_prop == 'description'"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: item.description != undefined && item.description != '' ? item.description : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`, content: item.description != undefined && item.description != '' ? item.description : `<span class='has-text-gray3 is-italic'>` + $i18n.get('label_value_not_provided') + `</span>`,
@ -173,7 +173,7 @@
column.metadatum !== 'row_description'" column.metadatum !== 'row_description'"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
popperClass: [ 'tainacan-tooltip', 'tooltip', column.metadata_type_object != undefined && column.metadata_type_object.component == 'tainacan-textarea' ? 'metadata-type-textarea' : '' ], popperClass: [ 'tainacan-tooltip', 'tooltip', column.metadata_type_object != undefined && column.metadata_type_object.component == 'tainacan-textarea' ? 'metadata-type-textarea' : '' ],
@ -204,7 +204,7 @@
<span <span
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 100, hide: 100,
}, },
content: $i18n.get('label_see_on_fullscreen'), content: $i18n.get('label_see_on_fullscreen'),

View File

@ -82,8 +82,8 @@ export const viewModesMixin = {
// Inserts information necessary for item by item navigation on single pages // Inserts information necessary for item by item navigation on single pages
this.queries['pos'] = ((this.queries['paged'] - 1) * this.queries['perpage']) + index; this.queries['pos'] = ((this.queries['paged'] - 1) * this.queries['perpage']) + index;
this.queries['source_list'] = this.termId ? 'term' : (!this.collectionId || this.collectionId == 'default' ? 'repository' : 'collection'); this.queries['source_list'] = this.termId ? 'term' : (!this.collectionId || this.collectionId == 'default' ? 'repository' : 'collection');
if ( this.$route && this.$route.path ) if ( this.$route && this.$route.href && this.$route.href.split('?') && this.$route.href.split('?').length )
this.queries['ref'] = this.$route.path; this.queries['ref'] = this.$route.href;
return itemUrl + '?' + qs.stringify(this.queries); return itemUrl + '?' + qs.stringify(this.queries);
} }
return itemUrl; return itemUrl;

View File

@ -94,6 +94,10 @@
bottom: 0; bottom: 0;
transition: top ease-in 0.75s, bottom ease-in 0.75s, position ease-in 0.75s; transition: top ease-in 0.75s, bottom ease-in 0.75s, position ease-in 0.75s;
&.horizontal-filters {
max-width: 100%;
}
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
padding: 0; padding: 0;
z-index: 99999; z-index: 99999;
@ -125,6 +129,12 @@
.modal-close { .modal-close {
display: none; display: none;
} }
&.horizontal-filters {
-webkit-flex: 0 1 100%;
-ms-flex: 0 1 100%;
flex: 0 1 100%;
}
} }
} }
@ -156,19 +166,66 @@
} }
} }
&.has-horizontal-filters {
.items-list-area {
max-width: 100%;
}
#filters-modal.horizontal-filters {
overflow: visible;
.modal-content,
.filters-components-list {
overflow: visible;
width: 100%;
max-width: 100% !important;
margin: 0;
box-sizing: border-box;
}
.filters-components-list {
margin-bottom: 0;
& > div {
display: inline-block;
vertical-align: text-top;
}
.filter-item-forms {
width: 100%;
min-width: var(--tainacan-filters-inline-width, 272px);
break-inside: avoid;
display: inline-block;
vertical-align: text-top;
margin-bottom: 1rem;
}
@media screen and (min-width: 769px) {
& > div:not(:last-child) {
margin-right: 2.25em;
}
.filter-item-forms {
width: var(--tainacan-filters-inline-width, 272px);
}
.filter-item-forms:not(:last-child) {
margin-right: 2.25em;
}
}
}
}
}
@media screen and (max-width: 768px) { @media screen and (max-width: 768px) {
&.is-filters-menu-open { &.is-filters-menu-open {
.items-list-area {
max-width: 100%;
}
.filters-menu { .filters-menu {
float: none; float: none;
max-width: 100%; max-width: 100%;
} }
.items-list-area { .items-list-area {
width: 100%; width: 100%;
} max-width: 100%;
#filter-menu-compress-button {
display: none;
} }
.filters-menu { .filters-menu {

View File

@ -32,6 +32,7 @@ import ThemeSearch from './theme.vue';
// Remaining imports // Remaining imports
import store from '../../../admin/js/store/store'; import store from '../../../admin/js/store/store';
import HelpButton from '../../../admin/components/other/help-button.vue';
import routerTheme from './theme-search/js/theme-router.js'; import routerTheme from './theme-search/js/theme-router.js';
import eventBusSearch from '../../../admin/js/event-bus-search'; import eventBusSearch from '../../../admin/js/event-bus-search';
import { import {
@ -76,7 +77,7 @@ export default (element) => {
const registeredViewModes = const registeredViewModes =
( tainacan_plugin && tainacan_plugin.registered_view_modes && tainacan_plugin.registered_view_modes.length ) ? ( tainacan_plugin && tainacan_plugin.registered_view_modes && tainacan_plugin.registered_view_modes.length ) ?
tainacan_plugin.registered_view_modes : tainacan_plugin.registered_view_modes :
[ 'table', 'cards', 'records', 'masonry', 'slideshow', 'list', 'map' ]; [ 'table', 'cards', 'records', 'masonry', 'mosaic', 'slideshow', 'list', 'map'];
// At first, we consider that all registered view modes are included. // At first, we consider that all registered view modes are included.
let possibleViewModes = registeredViewModes; let possibleViewModes = registeredViewModes;
@ -130,7 +131,10 @@ export default (element) => {
startWithFiltersHidden: isParameterTrue(getDataAttribute(blockElement, 'start-with-filters-hidden')), startWithFiltersHidden: isParameterTrue(getDataAttribute(blockElement, 'start-with-filters-hidden')),
filtersAsModal: isParameterTrue(getDataAttribute(blockElement, 'filters-as-modal')), filtersAsModal: isParameterTrue(getDataAttribute(blockElement, 'filters-as-modal')),
showInlineViewModeOptions: isParameterTrue(getDataAttribute(blockElement, 'show-inline-view-mode-options')), showInlineViewModeOptions: isParameterTrue(getDataAttribute(blockElement, 'show-inline-view-mode-options')),
showFullscreenWithViewModes: isParameterTrue(getDataAttribute(blockElement, 'show-fullscreen-with-view-modes')) showFullscreenWithViewModes: isParameterTrue(getDataAttribute(blockElement, 'show-fullscreen-with-view-modes')),
shouldNotHideFiltersOnMobile: isParameterTrue(getDataAttribute(blockElement, 'should-not-hide-filters-on-mobile')),
displayFiltersHorizontally: isParameterTrue(getDataAttribute(blockElement, 'display-filters-horizontally')),
hideFilterCollapses: isParameterTrue(getDataAttribute(blockElement, 'hide-filter-collapses')),
}), }),
}); });
@ -188,6 +192,7 @@ export default (element) => {
VueItemsList.use(AxiosErrorHandlerPlugin); VueItemsList.use(AxiosErrorHandlerPlugin);
VueItemsList.use(ConsolePlugin, {visual: false}); VueItemsList.use(ConsolePlugin, {visual: false});
VueItemsList.use(AdminOptionsHelperPlugin, blockElement.dataset['options']); VueItemsList.use(AdminOptionsHelperPlugin, blockElement.dataset['options']);
VueItemsList.component('help-button', HelpButton);
/* Registers Extra Vue Components passed to the window.tainacan_extra_components */ /* Registers Extra Vue Components passed to the window.tainacan_extra_components */
if (typeof window.tainacan_extra_components != "undefined") { if (typeof window.tainacan_extra_components != "undefined") {

View File

@ -31,7 +31,7 @@
id="filter-menu-compress-button" id="filter-menu-compress-button"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: !isFiltersModalActive ? $i18n.get('label_show_filters') : $i18n.get('label_hide_filters'), content: !isFiltersModalActive ? $i18n.get('label_show_filters') : $i18n.get('label_hide_filters'),
@ -41,12 +41,19 @@
}" }"
aria-controls="filters-modal" aria-controls="filters-modal"
:aria-expanded="isFiltersModalActive" :aria-expanded="isFiltersModalActive"
:class="hideHideFiltersButton ? 'is-hidden-tablet' : ''" :class="{
'is-hidden-tablet': !shouldNotHideFiltersOnMobile && hideHideFiltersButton,
'is-hidden': shouldNotHideFiltersOnMobile && hideHideFiltersButton
}"
:aria-label="!isFiltersModalActive ? $i18n.get('label_show_filters') : $i18n.get('label_hide_filters')" :aria-label="!isFiltersModalActive ? $i18n.get('label_show_filters') : $i18n.get('label_hide_filters')"
@click="isFiltersModalActive = !isFiltersModalActive"> @click="isFiltersModalActive = !isFiltersModalActive">
<span class="icon"> <span class="icon">
<i <i
:class="{ 'tainacan-icon-arrowleft' : isFiltersModalActive, 'tainacan-icon-arrowright' : !isFiltersModalActive }" :class="{
'tainacan-icon-arrowdown': isFiltersModalActive && displayFiltersHorizontally,
'tainacan-icon-arrowleft': isFiltersModalActive && !displayFiltersHorizontally,
'tainacan-icon-arrowright' : !isFiltersModalActive
}"
class="tainacan-icon tainacan-icon-1-25em" /> class="tainacan-icon tainacan-icon-1-25em" />
</span> </span>
<span class="text is-hidden-tablet">{{ $i18n.get('filters') }}</span> <span class="text is-hidden-tablet">{{ $i18n.get('filters') }}</span>
@ -149,7 +156,7 @@
ref="displayedMetadataDropdown" ref="displayedMetadataDropdown"
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: totalItems <= 0 ? $i18n.get('info_cant_select_metadata_without_items') : '', content: totalItems <= 0 ? $i18n.get('info_cant_select_metadata_without_items') : '',
@ -341,7 +348,7 @@
v-else v-else
v-tooltip="{ v-tooltip="{
delay: { delay: {
shown: 500, show: 500,
hide: 300, hide: 300,
}, },
content: registeredViewModes[viewModeOption].label, content: registeredViewModes[viewModeOption].label,
@ -406,7 +413,45 @@
<!-- SIDEBAR WITH FILTERS --> <!-- SIDEBAR WITH FILTERS -->
<template v-if="!hideFilters"> <template v-if="!hideFilters">
<template v-if="!filtersAsModal && shouldNotHideFiltersOnMobile">
<div
v-if="isFiltersModalActive"
id="filters-modal"
ref="filters-modal"
role="region"
:class="'tainacan-modal tainacan-form filters-menu' + (displayFiltersHorizontally ? ' horizontal-filters' : '')">
<div class="animation-content modal-content">
<!-- JS-side hook for extra form content -->
<div
v-if="hooks['filters_before']"
class="faceted-search-hook faceted-search-hook-filters-before"
v-html="hooks['filters_before']" />
<filters-items-list
id="filters-items-list"
:is-loading-items="isLoadingItems"
:taxonomy="taxonomy"
:collection-id="collectionId + ''"
:is-repository-level="isRepositoryLevel"
:filters-as-modal="false"
:has-filtered="hasFiltered"
:is-mobile-screen="isMobileScreen"
:hide-filter-collapses="hideFilterCollapses"
@update-is-loading-items-state="(state) => isLoadingItems = state" />
<!-- JS-side hook for extra form content -->
<div
v-if="hooks['filters_after']"
class="faceted-search-hook faceted-search-hook-filters-after"
v-html="hooks['filters_after']" />
</div>
</div>
</template>
<b-modal <b-modal
v-else
id="filters-modal" id="filters-modal"
ref="filters-modal" ref="filters-modal"
v-model="isFiltersModalActive" v-model="isFiltersModalActive"
@ -415,7 +460,7 @@
:auto-focus="filtersAsModal" :auto-focus="filtersAsModal"
:trap-focus="filtersAsModal" :trap-focus="filtersAsModal"
full-screen full-screen
:custom-class="'tainacan-modal tainacan-form filters-menu' + (filtersAsModal ? ' filters-menu-modal' : '')" :custom-class="'tainacan-modal tainacan-form filters-menu' + (filtersAsModal ? ' filters-menu-modal' : '') + (displayFiltersHorizontally ? ' horizontal-filters' : '')"
:can-cancel="hideHideFiltersButton || !filtersAsModal ? ['x', 'outside'] : ['x', 'escape', 'outside']" :can-cancel="hideHideFiltersButton || !filtersAsModal ? ['x', 'outside'] : ['x', 'escape', 'outside']"
:close-button-aria-label="$i18n.get('close')"> :close-button-aria-label="$i18n.get('close')">
@ -438,6 +483,7 @@
:filters-as-modal="filtersAsModal" :filters-as-modal="filtersAsModal"
:has-filtered="hasFiltered" :has-filtered="hasFiltered"
:is-mobile-screen="isMobileScreen" :is-mobile-screen="isMobileScreen"
:hide-filter-collapses="hideFilterCollapses"
@update-is-loading-items-state="(state) => isLoadingItems = state" /> @update-is-loading-items-state="(state) => isLoadingItems = state" />
<!-- JS-side hook for extra form content --> <!-- JS-side hook for extra form content -->
@ -737,7 +783,10 @@
startWithFiltersHidden: false, startWithFiltersHidden: false,
filtersAsModal: false, filtersAsModal: false,
showInlineViewModeOptions: false, showInlineViewModeOptions: false,
showFullscreenWithViewModes: false showFullscreenWithViewModes: false,
shouldNotHideFiltersOnMobile: false,
displayFiltersHorizontally: false,
hideFilterCollapses: false,
}, },
data() { data() {
return { return {
@ -790,6 +839,7 @@
}), }),
wrapperClasses() { wrapperClasses() {
return { return {
'has-horizontal-filters': this.displayFiltersHorizontally,
'is-filters-menu-open': !this.hideFilters && this.isFiltersModalActive && !this.openAdvancedSearch, 'is-filters-menu-open': !this.hideFilters && this.isFiltersModalActive && !this.openAdvancedSearch,
'is-filters-menu-fixed-at-top': this.isFiltersListFixedAtTop, 'is-filters-menu-fixed-at-top': this.isFiltersListFixedAtTop,
'is-filters-menu-fixed-at-bottom': this.isFiltersListFixedAtBottom, 'is-filters-menu-fixed-at-bottom': this.isFiltersListFixedAtBottom,
@ -1028,6 +1078,12 @@
} }
} }
// If any default items per page is set, apply it
// 12 is already the default value, se we don't set this value
if (this.defaultItemsPerPage != undefined && this.defaultItemsPerPage !== 12 ) {
this.$eventBusSearch.setItemsPerPage(this.defaultItemsPerPage, true);
}
for (let key in currentQuery) { for (let key in currentQuery) {
if (currentQuery[key] == 'true') if (currentQuery[key] == 'true')
currentQuery[key] = true; currentQuery[key] = true;
@ -1123,15 +1179,12 @@
} }
} }
// If any default items per page is set, apply it
if (this.defaultItemsPerPage)
this.$eventBusSearch.setItemsPerPage(this.defaultItemsPerPage, true);
// Watches window resize to adjust filter's top position and compression on mobile // Watches window resize to adjust filter's top position and compression on mobile
if (!this.hideFilters) { if ( !this.hideFilters && !this.shouldNotHideFiltersOnMobile ) {
this.hideFiltersOnMobile(); this.hideFiltersOnMobile();
window.addEventListener('resize', this.hideFiltersOnMobile); window.addEventListener('resize', this.hideFiltersOnMobile);
} else {
this.isFiltersModalActive = !this.startWithFiltersHidden;
} }
// Uses Intersection Observer o see if the top of the list is on screen and fix filters list position // Uses Intersection Observer o see if the top of the list is on screen and fix filters list position
@ -1589,7 +1642,7 @@
// Component // Component
this.$emitter.off(); this.$emitter.off();
// Window // Window
if (!this.hideFilters) if ( !this.hideFilters && !this.shouldNotHideFiltersOnMobile )
window.removeEventListener('resize', this.hideFiltersOnMobile); window.removeEventListener('resize', this.hideFiltersOnMobile);
// $root // $root
if (!this.hideAdvancedSearch) if (!this.hideAdvancedSearch)
@ -1925,7 +1978,7 @@
} }
&:last-child { &:last-child {
margin-right: auto; margin-right: 0;
} }
.label { .label {

View File

@ -7,6 +7,7 @@ import iconUrl from 'leaflet/dist/images/marker-icon.png';
import iconRetinaUrl from 'leaflet/dist/images/marker-icon-2x.png'; import iconRetinaUrl from 'leaflet/dist/images/marker-icon-2x.png';
import shadowUrl from 'leaflet/dist/images/marker-shadow.png'; import shadowUrl from 'leaflet/dist/images/marker-shadow.png';
// Defines custom marker icons
delete TainacanLeaflet.Icon.Default.prototype._getIconUrl; delete TainacanLeaflet.Icon.Default.prototype._getIconUrl;
TainacanLeaflet.Icon.Default.mergeOptions({ TainacanLeaflet.Icon.Default.mergeOptions({
iconRetinaUrl: iconRetinaUrl, iconRetinaUrl: iconRetinaUrl,
@ -14,6 +15,48 @@ TainacanLeaflet.Icon.Default.mergeOptions({
shadowUrl: shadowUrl shadowUrl: shadowUrl
}); });
// Observes the visibility of the map container to resize the map when it becomes visible
const mapObserverOptions = {
root: null, // use the viewport
rootMargin: '0px',
threshold: 0.1 // 10% of the element is visible
};
// The mapObserver repeats part of the initialization logic to prevent the map from looking broke
// when it becomes visible after being hidden, for example inside section tabs
const mapObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
if (
entry &&
entry.target.id &&
window.tainacan_leaflet_maps &&
window.tainacan_leaflet_maps[entry.target.id]
) {
const element = entry.target;
const children = element.children ? element.children : [];
if ( !children.length )
return;
const coordinates = [];
for (let i = 0; i < children.length; i++) {
if ( children[i].hasAttribute('data-latitude') && children[i].hasAttribute('data-longitude') )
coordinates.push([children[i].getAttribute('data-latitude'), children[i].getAttribute('data-longitude')]);
}
if ( !coordinates.length )
return;
const maximum_zoom = element.hasAttribute('data-maximum_zoom') ? element.getAttribute('data-maximum_zoom') : 12;
window.tainacan_leaflet_maps[element.id].invalidateSize(true);
window.tainacan_leaflet_maps[element.id].flyToBounds(coordinates, { maxZoom: maximum_zoom, animate: false });
}
}
});
}, mapObserverOptions);
/* Loads and instantiates map components passed to data-module="geocoordinate-item-metadatum"*/ /* Loads and instantiates map components passed to data-module="geocoordinate-item-metadatum"*/
export default (element) => { export default (element) => {
if (element && element.id) { if (element && element.id) {
@ -56,5 +99,11 @@ export default (element) => {
}); });
tainacanMap.flyToBounds(coordinates, { maxZoom: maximum_zoom }); tainacanMap.flyToBounds(coordinates, { maxZoom: maximum_zoom });
mapObserver.observe(element);
// Stores referenced to the leaflet instances to manipulate them via the window object inside the observer
window.tainacan_leaflet_maps = typeof window.tainacan_leaflet_maps != "undefined" ? window.tainacan_leaflet_maps : {};
window.tainacan_leaflet_maps[element.id] = tainacanMap;
} }
}; };

View File

@ -336,6 +336,7 @@ return apply_filters( 'tainacan-i18n', [
'label_grid' => __( 'Thumbnails', 'tainacan' ), 'label_grid' => __( 'Thumbnails', 'tainacan' ),
'label_table' => __( 'Table', 'tainacan' ), 'label_table' => __( 'Table', 'tainacan' ),
'label_cards' => __( 'Cards', 'tainacan' ), 'label_cards' => __( 'Cards', 'tainacan' ),
'label_mosaic' => __( 'Mosaic', 'tainacan' ),
/* translators: The 'records' view mode, in the sense of a catalog file */ /* translators: The 'records' view mode, in the sense of a catalog file */
'label_records' => __( 'Records', 'tainacan' ), 'label_records' => __( 'Records', 'tainacan' ),
'label_masonry' => __( 'Masonry', 'tainacan' ), 'label_masonry' => __( 'Masonry', 'tainacan' ),
@ -529,6 +530,7 @@ return apply_filters( 'tainacan-i18n', [
'label_view_all_%s_collections' => __( 'View all %s collections', 'tainacan' ), 'label_view_all_%s_collections' => __( 'View all %s collections', 'tainacan' ),
'label_view_collections_list' => __( 'View collections list', 'tainacan' ), 'label_view_collections_list' => __( 'View collections list', 'tainacan' ),
'label_comparator' => __( 'Comparator', 'tainacan' ), 'label_comparator' => __( 'Comparator', 'tainacan' ),
'label_comparators' => __( 'Comparators', 'tainacan' ),
'label_table_of_items' => __( 'Table of Items', 'tainacan' ), 'label_table_of_items' => __( 'Table of Items', 'tainacan' ),
'label_create_another_item' => __( 'Create another item', 'tainacan' ), 'label_create_another_item' => __( 'Create another item', 'tainacan' ),
'label_recent_collections' => __( 'Recent Collections', 'tainacan' ), 'label_recent_collections' => __( 'Recent Collections', 'tainacan' ),
@ -707,6 +709,7 @@ return apply_filters( 'tainacan-i18n', [
'label_item_submission_options' => __( 'Item submission options', 'tainacan' ), 'label_item_submission_options' => __( 'Item submission options', 'tainacan' ),
'label_metadata_related_features' => __( 'Metadata related features', 'tainacan' ), 'label_metadata_related_features' => __( 'Metadata related features', 'tainacan' ),
'label_preview' => __( 'Preview', 'tainacan' ), 'label_preview' => __( 'Preview', 'tainacan' ),
'label_go_to_permalinks' => __( 'Go to permalinks', 'tainacan' ),
// Instructions. More complex sentences to guide user and placeholders // Instructions. More complex sentences to guide user and placeholders
'instruction_delete_selected_collections' => __( 'Delete selected collections', 'tainacan' ), 'instruction_delete_selected_collections' => __( 'Delete selected collections', 'tainacan' ),
@ -788,6 +791,8 @@ return apply_filters( 'tainacan-i18n', [
'instruction_click_to_add_a_point' => __( 'Drag to reposition or click to insert a marker', 'tainacan' ), '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_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_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' ),
'instruction_select_second_numeric_to_compare' => __( 'Select the second numeric metadatum', 'tainacan' ),
// Info. Other feedback to user. // Info. Other feedback to user.
'info_items_tab_all' => __( 'Every item, except by those sent to trash.', 'tainacan' ), 'info_items_tab_all' => __( 'Every item, except by those sent to trash.', 'tainacan' ),
@ -1064,6 +1069,8 @@ return apply_filters( 'tainacan-i18n', [
'info_terms_creation_failed_due_to_value_%s' => __( 'Terms creation failed due to value: %s.', 'tainacan' ), 'info_terms_creation_failed_due_to_value_%s' => __( 'Terms creation failed due to value: %s.', 'tainacan' ),
'info_terms_creation_failed_due_to_values_%s' => __( 'Terms creation failed due to values: %s.', 'tainacan' ), 'info_terms_creation_failed_due_to_values_%s' => __( 'Terms creation failed due to values: %s.', 'tainacan' ),
'info_autodraft_updated' => __( 'Autodraft updated. Please create the item to keep your changes.', 'tainacan' ), 'info_autodraft_updated' => __( 'Autodraft updated. Please create the item to keep your changes.', 'tainacan' ),
'info_intersection_explainer' => __( 'Will show items if the selected value is:', 'tainacan' ),
'info_intersection_rules' => __( 'The value must match both rules to appear in the filter.', 'tainacan' ),
/* Activity actions */ /* Activity actions */
'action_update-metadata-value' => __( 'Item Metadata Value Updates', 'tainacan'), 'action_update-metadata-value' => __( 'Item Metadata Value Updates', 'tainacan'),
@ -1112,6 +1119,7 @@ return apply_filters( 'tainacan-i18n', [
/* Errors displayed on the interface bottom notifications */ /* Errors displayed on the interface bottom notifications */
'error_connectivity_label' => __('Connectivity issue', 'tainacan'), 'error_connectivity_label' => __('Connectivity issue', 'tainacan'),
'error_connectivity' => __('It is possible that you are disconnected or the server is not working properly.', 'tainacan'), 'error_connectivity' => __('It is possible that you are disconnected or the server is not working properly.', 'tainacan'),
'error_permalinks_label' => __('Permalinks issue', 'tainacan'),
'error_400' => __('Some request went wrong due to invalid syntax.', 'tainacan'), 'error_400' => __('Some request went wrong due to invalid syntax.', 'tainacan'),
'error_401' => __('You must authenticate to access this information. Try logging in again on the WordPress Admin panel.', 'tainacan'), 'error_401' => __('You must authenticate to access this information. Try logging in again on the WordPress Admin panel.', 'tainacan'),
'error_403' => __('It seems that you are not allowed to access this content.', 'tainacan'), 'error_403' => __('It seems that you are not allowed to access this content.', 'tainacan'),
@ -1124,6 +1132,7 @@ return apply_filters( 'tainacan-i18n', [
'error_511' => __('You must authenticate to get access this information. Try logging in again on the WordPress Admin panel.', 'tainacan'), 'error_511' => __('You must authenticate to get access this information. Try logging in again on the WordPress Admin panel.', 'tainacan'),
'error_other' => __('Something went wrong here. You may want to try again or contact the Administrator.', 'tainacan'), 'error_other' => __('Something went wrong here. You may want to try again or contact the Administrator.', 'tainacan'),
'error_connectivity_detail' => __('The WordPress Heartbit API sends requests periodically to the server to update some information. The latest request failed for some reason. It can be the case of a lost connection or bad communication between the browser and the server.', 'tainacan'), 'error_connectivity_detail' => __('The WordPress Heartbit API sends requests periodically to the server to update some information. The latest request failed for some reason. It can be the case of a lost connection or bad communication between the browser and the server.', 'tainacan'),
'error_permalinks_detail' => __( 'Tainacan requires your Permalink settings to be configured. Please visit %sPermalink settings%s and define it to an option such as "postname".', 'tainacan' ),
'error_400_detail' => __('The server could not understand the request due to invalid syntax. This is possibly an issue with Tainacan and should be reported to its developers.', 'tainacan'), 'error_400_detail' => __('The server could not understand the request due to invalid syntax. This is possibly an issue with Tainacan and should be reported to its developers.', 'tainacan'),
'error_401_detail' => __('You must authenticate to get access this information. Even if you have access to the Tainacan admin panel, it may be the case that your session cookies were lost. Try reloading the page or logging again on the WordPress Admin panel.', 'tainacan'), 'error_401_detail' => __('You must authenticate to get access this information. Even if you have access to the Tainacan admin panel, it may be the case that your session cookies were lost. Try reloading the page or logging again on the WordPress Admin panel.', 'tainacan'),
'error_403_detail' => __('It seems that you are not allowed to access this content. Your user might have a role with insufficient capabilities. If that is not the case, check if you are correctly logged in on the WordPress Admin panel.', 'tainacan'), 'error_403_detail' => __('It seems that you are not allowed to access this content. Your user might have a role with insufficient capabilities. If that is not the case, check if you are correctly logged in on the WordPress Admin panel.', 'tainacan'),

View File

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