Begins implementation of dynamic items list block with tainacan view modes. #872.
This commit is contained in:
parent
9289b36898
commit
40eba14fc6
|
@ -993,6 +993,19 @@
|
|||
.wp-block-tainacan-dynamic-items-list ul.items-list.items-layout-mosaic .mosaic-container,
|
||||
.wp-block-tainacan-dynamic-items-list ul.items-list-edit.items-layout-mosaic .mosaic-container {
|
||||
min-width: 240px; } }
|
||||
.wp-block-tainacan-dynamic-items-list .items-list.items-layout-tainacan-view-modes {
|
||||
--tainacan-container-padding: 0.875em; }
|
||||
.wp-block-tainacan-dynamic-items-list .items-list.items-layout-tainacan-view-modes h1,
|
||||
.wp-block-tainacan-dynamic-items-list .items-list.items-layout-tainacan-view-modes h2,
|
||||
.wp-block-tainacan-dynamic-items-list .items-list.items-layout-tainacan-view-modes h3,
|
||||
.wp-block-tainacan-dynamic-items-list .items-list.items-layout-tainacan-view-modes h4,
|
||||
.wp-block-tainacan-dynamic-items-list .items-list.items-layout-tainacan-view-modes h5,
|
||||
.wp-block-tainacan-dynamic-items-list .items-list.items-layout-tainacan-view-modes h6 {
|
||||
margin: 0; }
|
||||
.wp-block-tainacan-dynamic-items-list .items-list.items-layout-tainacan-view-modes ul {
|
||||
list-style: none; }
|
||||
.wp-block-tainacan-dynamic-items-list .items-list.items-layout-tainacan-view-modes .loading-overlay {
|
||||
min-height: auto !important; }
|
||||
|
||||
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-dynamic-items-list li.item-list-item a > span,
|
||||
.block-editor-block-list__block:not(.has-text-color) > .wp-block-tainacan-dynamic-items-list li.item-list-item a:hover > span {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1188,7 +1188,7 @@ class Theme_Helper {
|
|||
* @param array $args {
|
||||
* Optional. Array of arguments.
|
||||
* @type string $item_id The Item ID
|
||||
* @type string $items_list_layout The type of list to be rendered. Accepts 'grid', 'list', 'mosaic' and 'carousel'.
|
||||
* @type string $items_list_layout The type of list to be rendered. Accepts 'grid', 'list', 'mosaic', 'carousel' and 'tainacan-view-mode.
|
||||
* @type string $order Sorting direction to the related items query. Either 'desc' or 'asc'.
|
||||
* @type string $orderby Sortby metadata. By now we're accepting only 'title' and 'date'.
|
||||
* @type string $class_name Extra class to add to the wrapper, besides the default wp-block-tainacan-carousel-related-items
|
||||
|
@ -1265,15 +1265,44 @@ class Theme_Helper {
|
|||
? $block_args['image_size']
|
||||
: ($no_crop_images_to_square ? 'tainacan-medium-full' : 'tainacan-medium');
|
||||
|
||||
// Remove attribute description to avoid poluting HTML
|
||||
// No need to pass the complete item to avoid poluting HTML
|
||||
$related_group['items'] = array_map(
|
||||
function($el) use ($image_size) {
|
||||
function($el) use ($args) {
|
||||
|
||||
// In Tainacan View Modes, we fetch items from api so we only need ID
|
||||
if ( $args['items_list_layout'] === 'tainacan-view-modes' )
|
||||
return $el['id'];
|
||||
|
||||
// For other layouts, we simply remove attribute description
|
||||
unset($el['description']);
|
||||
return $el;
|
||||
}, $related_group['items']
|
||||
);
|
||||
|
||||
if ( isset($args['items_list_layout']) && $args['items_list_layout'] !== 'carousel' ) {
|
||||
if ( isset($args['items_list_layout']) && $args['items_list_layout'] === 'carousel' ) {
|
||||
$items_list_args = wp_parse_args([
|
||||
'collection_id' => $related_group['collection_id'],
|
||||
'load_strategy' => 'parent',
|
||||
'selected_items' => json_encode($related_group['items']),
|
||||
'image_size' => $image_size
|
||||
], $block_args);
|
||||
|
||||
$items_list_div = $this->get_tainacan_items_carousel($items_list_args);
|
||||
|
||||
} else if ( isset($args['items_list_layout']) && $args['items_list_layout'] === 'tainacan-view-modes' ) {
|
||||
$items_list_args = wp_parse_args([
|
||||
'collection_id' => $related_group['collection_id'],
|
||||
'load_strategy' => 'selection', // Tainacan View Modes fetch item from api to get item metadata as well
|
||||
'selected_items' => json_encode($related_group['items']),
|
||||
'layout' => $args['items_list_layout'],
|
||||
'displayed_metadata' => json_encode(isset( $block_args['displayed_metadata'] ) ? $block_args['displayed_metadata'] : []),
|
||||
'selected_items' => json_encode($related_group['items']),
|
||||
'tainacan_view_mode' => $block_args['tainacan_view_mode']
|
||||
], $block_args);
|
||||
|
||||
$items_list_div = $this->get_tainacan_dynamic_items_list($items_list_args);
|
||||
|
||||
} else {
|
||||
$items_list_args = wp_parse_args([
|
||||
'collection_id' => $related_group['collection_id'],
|
||||
'load_strategy' => 'parent',
|
||||
|
@ -1283,15 +1312,7 @@ class Theme_Helper {
|
|||
], $block_args);
|
||||
|
||||
$items_list_div = $this->get_tainacan_dynamic_items_list($items_list_args);
|
||||
} else {
|
||||
$items_list_args = wp_parse_args([
|
||||
'collection_id' => $related_group['collection_id'],
|
||||
'load_strategy' => 'parent',
|
||||
'selected_items' => json_encode($related_group['items']),
|
||||
'image_size' => $image_size
|
||||
], $block_args);
|
||||
|
||||
$items_list_div = $this->get_tainacan_items_carousel($items_list_args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1143,6 +1143,29 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rules for Tainacan View Modes are similar to those applied
|
||||
// for .theme-items-list in /blocks/faceted-search/theme.vue
|
||||
.items-list.items-layout-tainacan-view-modes {
|
||||
|
||||
// Not really used in EVERY container, but a rather frequent value
|
||||
--tainacan-container-padding: 0.875em;
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin: 0;
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
}
|
||||
.loading-overlay {
|
||||
min-height: auto !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.block-editor-block-list__block:not(.has-text-color)>.wp-block-tainacan-dynamic-items-list {
|
||||
li.item-list-item {
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
import { createApp, h } from 'vue';
|
||||
import { createApp, h, defineAsyncComponent } from 'vue';
|
||||
|
||||
import DynamicItemsListTheme from './theme.vue';
|
||||
import { ThumbnailHelperPlugin } from '../../../admin/js/utilities.js';
|
||||
import { I18NPlugin } from '../../../admin/js/admin-utilities';
|
||||
import VueBlurHash from 'another-vue3-blurhash';
|
||||
import VTooltip from 'floating-vue';
|
||||
|
||||
import getDataAttribute from '../../js/compatibility/tainacan-blocks-compat-data-attributes.js';
|
||||
|
||||
export default (element) => {
|
||||
|
@ -21,8 +24,31 @@ export default (element) => {
|
|||
// Creates a new Vue Instance to manage each block isolatelly
|
||||
blocks.forEach((block) => {
|
||||
|
||||
// View Modes Logic
|
||||
let registeredViewModes =
|
||||
( tainacan_blocks && tainacan_blocks.registered_view_modes && tainacan_blocks.registered_view_modes.length ) ?
|
||||
tainacan_blocks.registered_view_modes :
|
||||
[ 'table', 'cards', 'records', 'masonry', 'list', 'map' ];
|
||||
|
||||
// At first, we consider that all registered view modes are included.
|
||||
let possibleViewModes = registeredViewModes.filter((aViewMode) => aViewMode === 'slideshow');
|
||||
if ( getDataAttribute(block, 'enabled-view-modes') != undefined )
|
||||
possibleViewModes = getDataAttribute(block, 'enabled-view-modes').split(',');
|
||||
|
||||
// View Mode settings
|
||||
let possibleDefaultViewMode = 'masonry';
|
||||
if ( getDataAttribute(block, 'tainacan-view-mode') != undefined )
|
||||
possibleDefaultViewMode = getDataAttribute(block, 'tainacan-view-mode');
|
||||
|
||||
if ( possibleViewModes.indexOf(possibleDefaultViewMode) < 0 )
|
||||
possibleViewModes.push(possibleDefaultViewMode);
|
||||
|
||||
|
||||
// Configure Vue logic before passing it to constructor:
|
||||
const VueDynamicItemsList = createApp( {
|
||||
mounted() {
|
||||
block.classList.add('has-mounted');
|
||||
},
|
||||
render() {
|
||||
return h(DynamicItemsListTheme, {
|
||||
searchURL: getDataAttribute(block, 'search-url'),
|
||||
|
@ -50,14 +76,31 @@ export default (element) => {
|
|||
showCollectionLabel: getDataAttribute(block, 'show-collection-label', 'false') == 'true',
|
||||
collectionBackgroundColor: getDataAttribute(block, 'collection-background-color'),
|
||||
collectionTextColor: getDataAttribute(block, 'collection-text-color'),
|
||||
tainacanApiRoot: getDataAttribute(block, 'tainacan-api-root')
|
||||
tainacanApiRoot: getDataAttribute(block, 'tainacan-api-root'),
|
||||
tainacanViewMode: possibleDefaultViewMode,
|
||||
enabledViewModes: possibleViewModes,
|
||||
displayedMetadata: JSON.parse(getDataAttribute(block, 'displayed-metadata', '[]')),
|
||||
});
|
||||
},
|
||||
mounted() {
|
||||
block.classList.add('has-mounted');
|
||||
}
|
||||
});
|
||||
|
||||
// Logic for dynamic importing Tainacan oficial view modes only if they are necessary
|
||||
possibleViewModes.forEach(viewModeSlug => {
|
||||
if ( registeredViewModes.indexOf(viewModeSlug) >= 0 )
|
||||
VueDynamicItemsList.component('view-mode-' + viewModeSlug, defineAsyncComponent(() => import('../faceted-search/theme-search/components/view-mode-' + viewModeSlug + '.vue')));
|
||||
});
|
||||
VueDynamicItemsList.use(VTooltip, {
|
||||
popperTriggers: ['hover'],
|
||||
themes: {
|
||||
'taianacan-tooltip': {
|
||||
'$extend': 'tooltip',
|
||||
triggers: ['hover', 'focus', 'touch'],
|
||||
autoHide: true,
|
||||
html: true,
|
||||
}
|
||||
}
|
||||
});
|
||||
VueDynamicItemsList.use(I18NPlugin);
|
||||
VueDynamicItemsList.use(ThumbnailHelperPlugin);
|
||||
VueDynamicItemsList.use(VueBlurHash);
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@
|
|||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<template v-if="isLoading">
|
||||
<template v-if="isLoading && layout !== 'tainacan-view-modes'">
|
||||
<ul
|
||||
v-if="layout !== 'mosaic'"
|
||||
:style="{
|
||||
|
@ -186,7 +186,7 @@
|
|||
</template>
|
||||
<div v-else>
|
||||
<ul
|
||||
v-if="items.length > 0 && layout !== 'mosaic'"
|
||||
v-if="items.length > 0 && layout !== 'mosaic' && layout !== 'tainacan-view-modes'"
|
||||
:style="{
|
||||
gridGap: layout == 'grid' ? ((showName ? gridMargin + 24 : gridMargin) + 'px') : 'inherit',
|
||||
marginTop: (showSearchBar || showCollectionHeader) ? ((showName ? gridMargin + 24 : gridMargin) + 'px') : '0px'
|
||||
|
@ -261,6 +261,25 @@
|
|||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
<div
|
||||
v-if="layout === 'tainacan-view-modes'"
|
||||
class="items-list"
|
||||
:class="'items-layout-' + layout + (!showName ? ' items-list-without-margin' : '')">
|
||||
<div
|
||||
v-if="(!isLoading && !isLoadingMetadata ) && registeredViewModes !== undefined && registeredViewModes[tainacanViewMode] != undefined && registeredViewModes[tainacanViewMode].type == 'template'"
|
||||
v-html="itemsListTemplate" />
|
||||
<component
|
||||
:is="registeredViewModes[tainacanViewMode] != undefined ? registeredViewModes[tainacanViewMode].component : ''"
|
||||
v-if="registeredViewModes !== undefined && registeredViewModes[tainacanViewMode] != undefined && registeredViewModes[tainacanViewMode].type == 'component'"
|
||||
:collection-id="collectionId"
|
||||
:displayed-metadata="displayedMetadataObjects"
|
||||
:should-hide-items-thumbnail="false"
|
||||
:items="items"
|
||||
:is-filters-menu-compressed="true"
|
||||
:total-items="items.length"
|
||||
:is-loading="isLoadingMetadata || isLoading"
|
||||
:enabled-view-modes="enabledViewModes" />
|
||||
</div>
|
||||
<div
|
||||
v-else-if="!isLoading && items.length <= 0"
|
||||
class="spinner-container">
|
||||
|
@ -302,7 +321,10 @@ export default {
|
|||
showCollectionLabel: Boolean,
|
||||
collectionBackgroundColor: String,
|
||||
collectionTextColor: String,
|
||||
tainacanApiRoot: String
|
||||
tainacanApiRoot: String,
|
||||
enabledViewModes: Array,
|
||||
tainacanViewMode: String,
|
||||
displayedMetadata: Array
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -318,7 +340,11 @@ export default {
|
|||
paged: undefined,
|
||||
totalItems: 0,
|
||||
apiRoot: '',
|
||||
errorMessage: 'No items found.'
|
||||
errorMessage: 'No items found.',
|
||||
displayedMetadataObjects: [],
|
||||
isLoadingMetadata: false,
|
||||
itemsListTemplate: '',
|
||||
registeredViewModes: tainacan_blocks.registered_view_modes,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
@ -335,7 +361,10 @@ export default {
|
|||
if (this.showCollectionHeader)
|
||||
this.fetchCollectionForHeader();
|
||||
|
||||
this.fetchItems();
|
||||
if (this.layout == 'tainacan-view-modes' && this.registeredViewModes !== undefined && this.registeredViewModes[this.tainacanViewMode] != undefined && this.registeredViewModes[this.tainacanViewMode]['dynamic_metadata'] == true)
|
||||
this.fetchMetadata();
|
||||
else
|
||||
this.fetchItems();
|
||||
},
|
||||
methods: {
|
||||
wpI18n(string, context) {
|
||||
|
@ -374,7 +403,21 @@ export default {
|
|||
|
||||
this.localMaxItemsNumber = this.selectedItems.length;
|
||||
|
||||
let endpoint = '/collection/' + this.collectionId + '/items?' + qs.stringify({ postin: this.selectedItems, perpage: this.localMaxItemsNumber }) + '&orderby=post__in&fetch_only=title,url,thumbnail';
|
||||
let endpoint = '/collection/' + this.collectionId + '/items?' + qs.stringify({ postin: this.selectedItems, perpage: this.localMaxItemsNumber }) + '&orderby=post__in';
|
||||
|
||||
if (
|
||||
this.layout == 'tainacan-view-modes' &&
|
||||
this.registeredViewModes !== undefined &&
|
||||
this.registeredViewModes[this.tainacanViewMode] != undefined &&
|
||||
this.registeredViewModes[this.tainacanViewMode]['dynamic_metadata'] == true
|
||||
) {
|
||||
if ( this.displayedMetadataObjects.length > 0 )
|
||||
endpoint += '&fetch_only=title,url,thumbnail&fetch_only_meta=' + this.displayedMetadataObjects.map((aMetadatum) => aMetadatum.id).join(',');
|
||||
else
|
||||
endpoint += '&fetch_only=title,description,url,thumbnail';
|
||||
} else {
|
||||
endpoint += '&fetch_only=title,url,thumbnail';
|
||||
}
|
||||
|
||||
this.tainacanAxios.get(endpoint, { cancelToken: this.itemsRequestSource.token })
|
||||
.then(response => {
|
||||
|
@ -382,6 +425,9 @@ export default {
|
|||
for (let item of response.data.items)
|
||||
this.items.push(item);
|
||||
|
||||
if ( response.data.template )
|
||||
this.itemsListTemplate = response.data.template;
|
||||
|
||||
this.isLoading = false;
|
||||
this.totalItems = response.headers['x-wp-total'];
|
||||
|
||||
|
@ -475,6 +521,22 @@ export default {
|
|||
});
|
||||
}
|
||||
},
|
||||
fetchMetadata() {
|
||||
let metadataEndpoint = '/collection/' + this.collectionId + '/metadata/?nopaging=1';
|
||||
|
||||
if ( this.displayedMetadata != undefined && this.displayedMetadata.length > 0 )
|
||||
metadataEndpoint += '&' + qs.stringify({ postin: this.displayedMetadata });
|
||||
else
|
||||
metadataEndpoint += '&metakey=display&metavalue=yes';
|
||||
|
||||
this.isLoadingMetadata = true;
|
||||
this.tainacanAxios.get(metadataEndpoint)
|
||||
.then(response => {
|
||||
this.displayedMetadataObjects = response.data;
|
||||
this.fetchItems();
|
||||
this.isLoadingMetadata = false;
|
||||
});
|
||||
},
|
||||
mosaicPartition(items) {
|
||||
const partition = _.groupBy(items, (item, i) => {
|
||||
if (i % 2 == 0)
|
||||
|
|
|
@ -23,7 +23,7 @@ export const viewModesMixin = {
|
|||
},
|
||||
computed: {
|
||||
queries() {
|
||||
let currentQueries = JSON.parse(JSON.stringify(this.$route.query));
|
||||
let currentQueries = this.$route && this.$route.query ? JSON.parse(JSON.stringify(this.$route.query)) : {};
|
||||
if (currentQueries) {
|
||||
delete currentQueries['view_mode'];
|
||||
delete currentQueries['fetch_only'];
|
||||
|
@ -81,7 +81,8 @@ export const viewModesMixin = {
|
|||
// Inserts information necessary for item by item navigation on single pages
|
||||
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['ref'] = this.$route.path;
|
||||
if ( this.$route && this.$route.path )
|
||||
this.queries['ref'] = this.$route.path;
|
||||
return itemUrl + '?' + qs.stringify(this.queries);
|
||||
}
|
||||
return itemUrl;
|
||||
|
@ -122,10 +123,11 @@ export const viewModesMixin = {
|
|||
return metadata.value_as_html;
|
||||
},
|
||||
starSlideshowFromHere(index) {
|
||||
this.$router.replace({ query: {...this.$route.query, ...{'slideshow-from': index } }}).catch((error) => this.$console.log(error));
|
||||
if (this.$router && this.$route && this.$route.query)
|
||||
this.$router.replace({ query: {...this.$route.query, ...{'slideshow-from': index } }}).catch((error) => this.$console.log(error));
|
||||
},
|
||||
getPosInSet(index) {
|
||||
if (Number(this.queries.paged) !== NaN && Number(this.queries.perpage) !== NaN)
|
||||
if ( !isNaN(Number(this.queries.paged)) && !isNaN(Number(this.queries.perpage)) )
|
||||
return ((Number(this.queries.paged) - 1) * Number(this.queries.perpage)) + index + 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -221,7 +221,8 @@ function tainacan_blocks_get_plugin_js_settings(){
|
|||
'admin_url' => admin_url(),
|
||||
'site_url' => site_url(),
|
||||
'theme_items_list_url' => esc_url_raw( get_site_url() ) . '/' . \Tainacan\Theme_Helper::get_instance()->get_items_list_slug(),
|
||||
'collections_post_types' => $cpts
|
||||
'collections_post_types' => $cpts,
|
||||
'registered_view_modes' => \Tainacan\Theme_Helper::get_instance()->get_registered_view_modes(),
|
||||
];
|
||||
|
||||
return $settings;
|
||||
|
|
Loading…
Reference in New Issue