Begins creation of collections carousel block.
This commit is contained in:
parent
2c7c7cbff0
commit
f61f8ef550
|
@ -18,6 +18,7 @@ function tainacan_blocks_add_gutenberg_blocks_actions() {
|
||||||
add_action('init', 'tainacan_blocks_register_tainacan_dynamic_items_list');
|
add_action('init', 'tainacan_blocks_register_tainacan_dynamic_items_list');
|
||||||
add_action('init', 'tainacan_blocks_register_tainacan_carousel_items_list');
|
add_action('init', 'tainacan_blocks_register_tainacan_carousel_items_list');
|
||||||
add_action('init', 'tainacan_blocks_register_tainacan_collections_list');
|
add_action('init', 'tainacan_blocks_register_tainacan_collections_list');
|
||||||
|
add_action('init', 'tainacan_blocks_register_tainacan_carousel_collections_list');
|
||||||
add_action('init', 'tainacan_blocks_register_tainacan_facets_list');
|
add_action('init', 'tainacan_blocks_register_tainacan_facets_list');
|
||||||
|
|
||||||
add_action('init', 'tainacan_blocks_add_plugin_settings');
|
add_action('init', 'tainacan_blocks_add_plugin_settings');
|
||||||
|
@ -197,6 +198,36 @@ function tainacan_blocks_register_tainacan_collections_list(){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function tainacan_blocks_register_tainacan_carousel_collections_list(){
|
||||||
|
global $TAINACAN_BASE_URL;
|
||||||
|
|
||||||
|
wp_enqueue_script(
|
||||||
|
'carousel-collections-list-theme',
|
||||||
|
$TAINACAN_BASE_URL . '/assets/gutenberg_carousel_collections_list_theme-components.js',
|
||||||
|
array('wp-components')
|
||||||
|
);
|
||||||
|
|
||||||
|
wp_register_script(
|
||||||
|
'carousel-collections-list',
|
||||||
|
$TAINACAN_BASE_URL . '/assets/gutenberg_carousel_collections_list-components.js',
|
||||||
|
array('wp-blocks', 'wp-element', 'wp-components', 'wp-editor')
|
||||||
|
);
|
||||||
|
|
||||||
|
wp_register_style(
|
||||||
|
'carousel-collections-list',
|
||||||
|
$TAINACAN_BASE_URL . '/assets/css/tainacan-gutenberg-block-carousel-collections-list.css',
|
||||||
|
array('wp-edit-blocks')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (function_exists('register_block_type')) {
|
||||||
|
register_block_type( 'tainacan/carousel-collections-list', array(
|
||||||
|
'editor_script' => 'carousel-collections-list',
|
||||||
|
'style' => 'carousel-collections-list',
|
||||||
|
'script' => 'carousel-collections-list-theme'
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function tainacan_blocks_get_plugin_js_settings(){
|
function tainacan_blocks_get_plugin_js_settings(){
|
||||||
global $TAINACAN_BASE_URL;
|
global $TAINACAN_BASE_URL;
|
||||||
|
|
||||||
|
@ -221,5 +252,6 @@ function tainacan_blocks_add_plugin_settings() {
|
||||||
wp_localize_script( 'dynamic-items-list', 'tainacan_plugin', $settings );
|
wp_localize_script( 'dynamic-items-list', 'tainacan_plugin', $settings );
|
||||||
wp_localize_script( 'carousel-items-list', 'tainacan_plugin', $settings );
|
wp_localize_script( 'carousel-items-list', 'tainacan_plugin', $settings );
|
||||||
wp_localize_script( 'collections-list', 'tainacan_plugin', $settings );
|
wp_localize_script( 'collections-list', 'tainacan_plugin', $settings );
|
||||||
|
wp_localize_script( 'carousel-collections-list', 'tainacan_plugin', $settings );
|
||||||
wp_localize_script( 'facets-list', 'tainacan_plugin', $settings );
|
wp_localize_script( 'facets-list', 'tainacan_plugin', $settings );
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
import Vue from 'vue';
|
||||||
|
import CarouselCollectionsListTheme from './carousel-collections-list-theme.vue';
|
||||||
|
|
||||||
|
// This is rendered on the theme side.
|
||||||
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
|
|
||||||
|
// Configure Vue logic before passing it to constructor:
|
||||||
|
let vueOptions = {
|
||||||
|
data: {
|
||||||
|
collectionId: '',
|
||||||
|
selectedItems: [],
|
||||||
|
maxItemsNumber: 12,
|
||||||
|
arrowsPosition: 'around',
|
||||||
|
autoPlay: false,
|
||||||
|
autoPlaySpeed: 3,
|
||||||
|
loopSlides: false,
|
||||||
|
hideTitle: true,
|
||||||
|
tainacanApiRoot: '',
|
||||||
|
tainacanBaseUrl: '',
|
||||||
|
className: '',
|
||||||
|
extraParams: {}
|
||||||
|
},
|
||||||
|
render(h){
|
||||||
|
return h(CarouselCollectionsListTheme, {
|
||||||
|
props: {
|
||||||
|
collectionId: this.collectionId,
|
||||||
|
selectedItems: this.selectedItems,
|
||||||
|
maxItemsNumber: this.maxItemsNumber,
|
||||||
|
arrowsPosition: this.arrowsPosition,
|
||||||
|
autoPlay: this.autoPlay,
|
||||||
|
autoPlaySpeed: this.autoPlaySpeed,
|
||||||
|
loopSlides: this.loopSlides,
|
||||||
|
hideTitle: this.hideTitle,
|
||||||
|
tainacanApiRoot: this.tainacanApiRoot,
|
||||||
|
tainacanBaseUrl: this.tainacanBaseUrl,
|
||||||
|
className: this.className,
|
||||||
|
extraParams: this.extraParams
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
beforeMount () {
|
||||||
|
this.className = this.$el.attributes.class != undefined ? this.$el.attributes.class.value : undefined;
|
||||||
|
this.selectedItems = this.$el.attributes['selected-collections'] != undefined ? JSON.parse(this.$el.attributes['selected-collections'].value) : undefined;
|
||||||
|
this.collectionId = this.$el.attributes['collection-id'] != undefined ? this.$el.attributes['collection-id'].value : undefined;
|
||||||
|
this.maxItemsNumber = this.$el.attributes['max-collections-number'] != undefined ? this.$el.attributes['max-collections-number'].value : undefined;
|
||||||
|
this.arrowsPosition = this.$el.attributes['arrows-position'] != undefined ? this.$el.attributes['arrows-position'].value : undefined;
|
||||||
|
this.autoPlay = this.$el.attributes['auto-play'] != undefined ? this.$el.attributes['auto-play'].value == 'true' : false;
|
||||||
|
this.autoPlaySpeed = this.$el.attributes['auto-play-speed'] != undefined ? this.$el.attributes['auto-play-speed'].value : 3;
|
||||||
|
this.loopSlides = this.$el.attributes['loop-slides'] != undefined ? this.$el.attributes['loop-slides'].value == 'true' : false;
|
||||||
|
this.hideTitle = this.$el.attributes['hide-title'] != undefined ? this.$el.attributes['hide-title'].value == 'true' : false;
|
||||||
|
this.tainacanApiRoot = this.$el.attributes['tainacan-api-root'] != undefined ? this.$el.attributes['tainacan-api-root'].value : undefined;
|
||||||
|
this.tainacanBaseUrl = this.$el.attributes['tainacan-base-url'] != undefined ? this.$el.attributes['tainacan-base-url'].value : undefined;
|
||||||
|
this.extraParams = this.$el.attributes['extra-params'] != undefined ? JSON.parse(this.$el.attributes['extra-params'].value) : undefined;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
__(text, domain) {
|
||||||
|
return wp.i18n.__(text, domain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Gets all divs with content created by our block;
|
||||||
|
let blocks = document.getElementsByClassName('wp-block-tainacan-carousel-collections-list');
|
||||||
|
|
||||||
|
if (blocks) {
|
||||||
|
let blockIds = Object.values(blocks).map((block) => block.id);
|
||||||
|
|
||||||
|
// Creates a new Vue Instance to manage each block isolatelly
|
||||||
|
for (let blockId of blockIds) {
|
||||||
|
new Vue( Object.assign({ el: '#' + blockId }, jQuery.extend(true, {}, vueOptions)) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,221 @@
|
||||||
|
<template>
|
||||||
|
<div :class="className">
|
||||||
|
<div v-if="!isLoading">
|
||||||
|
<div
|
||||||
|
:class="'tainacan-carousel has-arrows-' + arrowsPosition"
|
||||||
|
v-if="collections.length > 0">
|
||||||
|
<swiper
|
||||||
|
role="list"
|
||||||
|
:options="swiperOptions">
|
||||||
|
<swiper-slide
|
||||||
|
role="listitem"
|
||||||
|
:key="index"
|
||||||
|
v-for="(collection, index) of collections"
|
||||||
|
class="collection-list-item">
|
||||||
|
<a
|
||||||
|
:id="isNaN(collection.id) ? collection.id : 'collection-id-' + collection.id"
|
||||||
|
:href="collection.url"
|
||||||
|
target="_blank">
|
||||||
|
<img
|
||||||
|
:src="
|
||||||
|
collection.thumbnail && collection.thumbnail['tainacan-medium'][0] && collection.thumbnail['tainacan-medium'][0]
|
||||||
|
?
|
||||||
|
collection.thumbnail['tainacan-medium'][0]
|
||||||
|
:
|
||||||
|
(collection.thumbnail && collection.thumbnail['thumbnail'][0] && collection.thumbnail['thumbnail'][0]
|
||||||
|
?
|
||||||
|
collection.thumbnail['thumbnail'][0]
|
||||||
|
:
|
||||||
|
`${tainacanBaseUrl}/admin/images/placeholder_square.png`)
|
||||||
|
"
|
||||||
|
:alt="collection.title ? collection.title : $root.__('Thumbnail', 'tainacan')">
|
||||||
|
<span v-if="!hideTitle">{{ collection.title ? collection.title : '' }}</span>
|
||||||
|
</a>
|
||||||
|
</swiper-slide>
|
||||||
|
</swiper>
|
||||||
|
<button
|
||||||
|
class="swiper-button-prev"
|
||||||
|
slot="button-prev">
|
||||||
|
<svg
|
||||||
|
width="42"
|
||||||
|
height="42"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
|
||||||
|
<path
|
||||||
|
d="M0 0h24v24H0z"
|
||||||
|
fill="none"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="swiper-button-next"
|
||||||
|
slot="button-next">
|
||||||
|
<svg
|
||||||
|
width="42"
|
||||||
|
height="42"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
|
||||||
|
<path
|
||||||
|
d="M0 0h24v24H0z"
|
||||||
|
fill="none"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="spinner-container">
|
||||||
|
{{ $root.__('No collections found.', 'tainacan') }}
|
||||||
|
</div>
|
||||||
|
<!-- Swiper buttons are hidden as they actually swipe from slide to slide -->
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<div :class="'tainacan-carousel has-arrows-' + arrowsPosition">
|
||||||
|
<swiper
|
||||||
|
role="list"
|
||||||
|
:options="swiperOptions">
|
||||||
|
<swiper-slide
|
||||||
|
role="listitem"
|
||||||
|
:key="index"
|
||||||
|
v-for="(collection, index) of 18"
|
||||||
|
class="collection-list-item skeleton">
|
||||||
|
<a>
|
||||||
|
<img>
|
||||||
|
<span v-if="!hideTitle" />
|
||||||
|
</a>
|
||||||
|
</swiper-slide>
|
||||||
|
</swiper>
|
||||||
|
<button
|
||||||
|
class="swiper-button-prev"
|
||||||
|
slot="button-prev">
|
||||||
|
<svg
|
||||||
|
width="42"
|
||||||
|
height="42"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
|
||||||
|
<path
|
||||||
|
d="M0 0h24v24H0z"
|
||||||
|
fill="none"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="swiper-button-next"
|
||||||
|
slot="button-next">
|
||||||
|
<svg
|
||||||
|
width="42"
|
||||||
|
height="42"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
|
||||||
|
<path
|
||||||
|
d="M0 0h24v24H0z"
|
||||||
|
fill="none"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios';
|
||||||
|
import qs from 'qs';
|
||||||
|
import 'swiper/dist/css/swiper.css';
|
||||||
|
import { swiper, swiperSlide } from 'vue-awesome-swiper';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "CarouselCollectionsListTheme",
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
collections: [],
|
||||||
|
collection: undefined,
|
||||||
|
itemsRequestSource: undefined,
|
||||||
|
isLoading: false,
|
||||||
|
isLoadingCollection: false,
|
||||||
|
localMaxCollectionsNumber: undefined,
|
||||||
|
localOrder: undefined,
|
||||||
|
tainacanAxios: undefined,
|
||||||
|
paged: undefined,
|
||||||
|
totalCollections: 0,
|
||||||
|
swiperOptions: {
|
||||||
|
mousewheel: true,
|
||||||
|
observer: true,
|
||||||
|
preventInteractionOnTransition: true,
|
||||||
|
allowClick: true,
|
||||||
|
allowTouchMove: true,
|
||||||
|
slidesPerView: 7,
|
||||||
|
slidesPerGroup: 1,
|
||||||
|
spaceBetween: 32,
|
||||||
|
slideToClickedSlide: true,
|
||||||
|
navigation: {
|
||||||
|
nextEl: '.swiper-button-next',
|
||||||
|
prevEl: '.swiper-button-prev',
|
||||||
|
},
|
||||||
|
breakpoints: {
|
||||||
|
498: { slidesPerView: 2 },
|
||||||
|
768: { slidesPerView: 3 },
|
||||||
|
1024: { slidesPerView: 4 },
|
||||||
|
1366: { slidesPerView: 5 },
|
||||||
|
1600: { slidesPerView: 6 },
|
||||||
|
},
|
||||||
|
autoplay: this.autoPlay ? { delay: this.autoPlaySpeed*1000 } : false,
|
||||||
|
loop: this.loopSlides
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
swiper,
|
||||||
|
swiperSlide
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
collectionId: String,
|
||||||
|
searchURL: String,
|
||||||
|
selectedCollections: Array,
|
||||||
|
maxCollectionsNumber: Number,
|
||||||
|
arrowsPosition: String,
|
||||||
|
autoPlay: false,
|
||||||
|
autoPlaySpeed: Number,
|
||||||
|
loopSlides: Boolean,
|
||||||
|
hideTitle: Boolean,
|
||||||
|
tainacanApiRoot: String,
|
||||||
|
tainacanBaseUrl: String,
|
||||||
|
className: String
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetchCollections() {
|
||||||
|
|
||||||
|
this.isLoading = true;
|
||||||
|
|
||||||
|
if (this.itemsRequestSource != undefined && typeof this.itemsRequestSource == 'function')
|
||||||
|
this.itemsRequestSource.cancel('Previous collections search canceled.');
|
||||||
|
|
||||||
|
this.itemsRequestSource = axios.CancelToken.source();
|
||||||
|
|
||||||
|
let endpoint = '/collection/' + this.collectionId + '/collections?' + qs.stringify({ postin: this.selectedCollections }) + '&fetch_only=title,url,thumbnail';
|
||||||
|
|
||||||
|
this.tainacanAxios.get(endpoint, { cancelToken: this.itemsRequestSource.token })
|
||||||
|
.then(response => {
|
||||||
|
|
||||||
|
for (let collection of response.data.collections)
|
||||||
|
this.collections.push(collection);
|
||||||
|
|
||||||
|
this.isLoading = false;
|
||||||
|
this.totalCollections = response.headers['x-wp-total'];
|
||||||
|
|
||||||
|
}).catch(() => {
|
||||||
|
this.isLoading = false;
|
||||||
|
// console.log(error);
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.tainacanAxios = axios.create({ baseURL: this.tainacanApiRoot });
|
||||||
|
|
||||||
|
this.fetchCollections();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
|
||||||
|
@import './carousel-collections-list.scss';
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,223 @@
|
||||||
|
@import '../../gutenberg-blocks-style.scss';
|
||||||
|
|
||||||
|
.wp-block-tainacan-carousel-collections-list {
|
||||||
|
margin: 2rem 0px;
|
||||||
|
|
||||||
|
// Spinner
|
||||||
|
.spinner-container {
|
||||||
|
min-height: 56px;
|
||||||
|
padding: 1rem;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: #555758;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skeleton loading
|
||||||
|
@-webkit-keyframes skeleton-animation {
|
||||||
|
0%{opacity: 1.0}
|
||||||
|
50%{opacity: 0.2}
|
||||||
|
100%{opacity: 1.0}
|
||||||
|
}
|
||||||
|
@-moz-keyframes skeleton-animation {
|
||||||
|
0%{opacity: 1.0}
|
||||||
|
50%{opacity: 0.2}
|
||||||
|
100%{opacity: 1.0}
|
||||||
|
}
|
||||||
|
@-o-keyframes skeleton-animation {
|
||||||
|
0%{opacity: 1.0}
|
||||||
|
50%{opacity: 0.2}
|
||||||
|
100%{opacity: 1.0}
|
||||||
|
}
|
||||||
|
@keyframes skeleton-animation {
|
||||||
|
0%{opacity: 1.0}
|
||||||
|
50%{opacity: 0.2}
|
||||||
|
100%{opacity: 1.0}
|
||||||
|
}
|
||||||
|
.skeleton {
|
||||||
|
border-radius: 2px;
|
||||||
|
background: #f2f2f2;
|
||||||
|
|
||||||
|
-webkit-animation: skeleton-animation 1.8s ease infinite;
|
||||||
|
-moz-animation: skeleton-animation 1.8s ease infinite;
|
||||||
|
-o-animation: skeleton-animation 1.8s ease infinite;
|
||||||
|
animation: skeleton-animation 1.8s ease infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tainacan Carousel
|
||||||
|
.tainacan-carousel {
|
||||||
|
position: relative;
|
||||||
|
width: calc(100% + 50px);
|
||||||
|
left: -50px;
|
||||||
|
|
||||||
|
.swiper-container {
|
||||||
|
margin: 0 50px;
|
||||||
|
|
||||||
|
a>span,
|
||||||
|
a:hover>span {
|
||||||
|
color: black;
|
||||||
|
font-weight: bold;
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 8px 16px;
|
||||||
|
display: block;
|
||||||
|
line-height: 1.2rem;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-warning {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-style: italic;
|
||||||
|
color: #898d8f;
|
||||||
|
text-align: center;
|
||||||
|
margin: 4px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next and previous buttons
|
||||||
|
.swiper-button-prev, .swiper-button-next {
|
||||||
|
top: initial;
|
||||||
|
bottom: calc(50% + 10px);
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 -4px;
|
||||||
|
|
||||||
|
svg {
|
||||||
|
fill: #298596;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Carousel placeholder on editor side ----------------------------------------------------
|
||||||
|
.items-list-edit-container,
|
||||||
|
.tainacan-carousel {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
& .skeleton {
|
||||||
|
min-height: 150px;
|
||||||
|
max-height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.has-arrows-none .swiper-button-prev,
|
||||||
|
&.has-arrows-none .swiper-button-next {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&.has-arrows-left .swiper-button-next {
|
||||||
|
left: 10px;
|
||||||
|
right: auto;
|
||||||
|
bottom: calc(50% + 36px);
|
||||||
|
}
|
||||||
|
&.has-arrows-right .swiper-button-prev {
|
||||||
|
right: 10px;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
&.has-arrows-right .swiper-button-next {
|
||||||
|
bottom: calc(50% + 36px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ul.items-list-edit {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
overflow-x: scroll;
|
||||||
|
list-style: none;
|
||||||
|
margin: 0 36px;
|
||||||
|
|
||||||
|
li.collection-list-item {
|
||||||
|
position: relative;
|
||||||
|
display: block;
|
||||||
|
margin: 16px;
|
||||||
|
width: calc(14.286% - 32px);
|
||||||
|
min-width: calc(14.286% - 32px);
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #454647;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: auto;
|
||||||
|
|
||||||
|
padding: 0px;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover a {
|
||||||
|
color: #454647;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
position: absolute !important;
|
||||||
|
background-color: rgba(255, 255, 255, 0.75);
|
||||||
|
color: #454647;
|
||||||
|
padding: 2px;
|
||||||
|
margin-left: 5px;
|
||||||
|
min-width: 14px;
|
||||||
|
visibility: hidden;
|
||||||
|
position: relative;
|
||||||
|
opacity: 0;
|
||||||
|
right: -14px;
|
||||||
|
top: 0px;
|
||||||
|
justify-content: center;
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover button {
|
||||||
|
visibility: visible;
|
||||||
|
background-color: rgba(255, 255, 255, 1) !important;
|
||||||
|
opacity: 1;
|
||||||
|
right: -8px;
|
||||||
|
top: -8px;
|
||||||
|
border: 1px solid #cbcbcb;
|
||||||
|
border-radius: 12px;
|
||||||
|
transition: opacity linear 0.15s, right linear 0.15s;
|
||||||
|
}
|
||||||
|
&:hover button:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 1) !important;
|
||||||
|
border: 1px solid #cbcbcb !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 1686px) {
|
||||||
|
|
||||||
|
ul.items-list-edit li.collection-list-item {
|
||||||
|
width: calc(16.666% - 32px);
|
||||||
|
min-width: calc(16.666% - 32px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 1452px) {
|
||||||
|
|
||||||
|
ul.items-list-edit li.collection-list-item {
|
||||||
|
width: calc(20% - 32px);
|
||||||
|
min-width: calc(20% - 32px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 1118px) {
|
||||||
|
|
||||||
|
ul.items-list-edit li.collection-list-item {
|
||||||
|
width: calc(25% - 32px);
|
||||||
|
min-width: calc(25% - 32px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 854px) {
|
||||||
|
|
||||||
|
ul.items-list-edit li.collection-list-item {
|
||||||
|
width: calc(33.333% - 32px);
|
||||||
|
min-width: calc(33.333% - 32px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media only screen and (max-width: 584px) {
|
||||||
|
|
||||||
|
ul.items-list-edit li.collection-list-item {
|
||||||
|
width: calc(50% - 32px);
|
||||||
|
min-width: calc(50% - 32px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,320 @@
|
||||||
|
import tainacan from '../../api-client/axios.js';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
const { __ } = wp.i18n;
|
||||||
|
|
||||||
|
const { TextControl, Button, Modal, RadioControl, Spinner } = wp.components;
|
||||||
|
|
||||||
|
export default class CarouselCollectionsModal extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
// Initialize state
|
||||||
|
this.state = {
|
||||||
|
collectionsPerPage: 24,
|
||||||
|
collectionId: undefined,
|
||||||
|
collectionName: '',
|
||||||
|
isLoadingCollections: false,
|
||||||
|
modalCollections: [],
|
||||||
|
totalModalCollections: 0,
|
||||||
|
collectionPage: 1,
|
||||||
|
temporaryCollectionId: '',
|
||||||
|
searchCollectionName: '',
|
||||||
|
collections: [],
|
||||||
|
collectionsRequestSource: undefined,
|
||||||
|
searchURL: '',
|
||||||
|
itemsPerPage: 12,
|
||||||
|
loadStrategy: 'search'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bind events
|
||||||
|
this.resetCollections = this.resetCollections.bind(this);
|
||||||
|
this.selectCollection = this.selectCollection.bind(this);
|
||||||
|
this.fetchCollections = this.fetchCollections.bind(this);
|
||||||
|
this.fetchModalCollections = this.fetchModalCollections.bind(this);
|
||||||
|
this.fetchCollection = this.fetchCollection.bind(this);
|
||||||
|
this.applySelectedSearchURL = this.applySelectedSearchURL.bind(this);
|
||||||
|
this.applySelectedItems = this.applySelectedItems.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
collectionId: this.props.existingCollectionId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.props.existingCollectionId != null && this.props.existingCollectionId != undefined) {
|
||||||
|
this.fetchCollection(this.props.existingCollectionId);
|
||||||
|
this.setState({
|
||||||
|
searchURL: this.props.existingSearchURL ? this.props.existingSearchURL : tainacan_plugin.admin_url + 'admin.php?page=tainacan_admin#/collections/'+ this.props.existingCollectionId + (this.props.loadStrategy == 'search' ? '/items/?iframemode=true&readmode=true' : '/items/?iframemode=true') });
|
||||||
|
} else {
|
||||||
|
this.setState({ collectionPage: 1 });
|
||||||
|
this.fetchModalCollections();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// COLLECTIONS RELATED --------------------------------------------------
|
||||||
|
fetchModalCollections() {
|
||||||
|
|
||||||
|
let someModalCollections = this.state.modalCollections;
|
||||||
|
if (this.state.collectionPage <= 1)
|
||||||
|
someModalCollections = [];
|
||||||
|
|
||||||
|
let endpoint = '/collections/?orderby=title&order=asc&perpage=' + this.state.collectionsPerPage + '&paged=' + this.state.collectionPage;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
isLoadingCollections: true,
|
||||||
|
collectionPage: this.state.collectionPage + 1,
|
||||||
|
modalCollections: someModalCollections
|
||||||
|
});
|
||||||
|
|
||||||
|
tainacan.get(endpoint)
|
||||||
|
.then(response => {
|
||||||
|
|
||||||
|
let otherModalCollections = this.state.modalCollections;
|
||||||
|
for (let collection of response.data) {
|
||||||
|
otherModalCollections.push({
|
||||||
|
name: collection.name,
|
||||||
|
id: collection.id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
isLoadingCollections: false,
|
||||||
|
modalCollections: otherModalCollections,
|
||||||
|
totalModalCollections: response.headers['x-wp-total']
|
||||||
|
});
|
||||||
|
|
||||||
|
return otherModalCollections;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log('Error trying to fetch collections: ' + error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCollection(collectionId) {
|
||||||
|
tainacan.get('/collections/' + collectionId)
|
||||||
|
.then((response) => {
|
||||||
|
this.setState({ collectionName: response.data.name });
|
||||||
|
}).catch(error => {
|
||||||
|
console.log('Error trying to fetch collection: ' + error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
selectCollection(selectedCollectionId) {
|
||||||
|
this.setState({
|
||||||
|
collectionId: selectedCollectionId,
|
||||||
|
searchURL: tainacan_plugin.admin_url + 'admin.php?page=tainacan_admin#/collections/' + selectedCollectionId + (this.props.loadStrategy == 'search' ? '/items/?iframemode=true&readmode=true' : '/items/?iframemode=true')
|
||||||
|
});
|
||||||
|
|
||||||
|
this.props.onSelectCollection(selectedCollectionId);
|
||||||
|
this.fetchCollection(selectedCollectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchCollections(name) {
|
||||||
|
|
||||||
|
if (this.state.collectionsRequestSource != undefined)
|
||||||
|
this.state.collectionsRequestSource.cancel('Previous collections search canceled.');
|
||||||
|
|
||||||
|
let aCollectionRequestSource = axios.CancelToken.source();
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
collectionsRequestSource: aCollectionRequestSource,
|
||||||
|
isLoadingCollections: true,
|
||||||
|
collections: [],
|
||||||
|
items: []
|
||||||
|
});
|
||||||
|
|
||||||
|
let endpoint = '/collections/?orderby=title&order=asc&perpage=' + this.state.collectionsPerPage;
|
||||||
|
if (name != undefined && name != '')
|
||||||
|
endpoint += '&search=' + name;
|
||||||
|
|
||||||
|
tainacan.get(endpoint, { cancelToken: aCollectionRequestSource.token })
|
||||||
|
.then(response => {
|
||||||
|
let someCollections = response.data.map((collection) => ({ name: collection.name, id: collection.id + '' }));
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
isLoadingCollections: false,
|
||||||
|
collections: someCollections
|
||||||
|
});
|
||||||
|
|
||||||
|
return someCollections;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log('Error trying to fetch collections: ' + error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
applySelectedSearchURL() {
|
||||||
|
let iframe = document.getElementById("itemsFrame");
|
||||||
|
if (iframe) {
|
||||||
|
this.props.onApplySearchURL(iframe.contentWindow.location.href);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
applySelectedItems() {
|
||||||
|
let iframe = document.getElementById("itemsFrame");
|
||||||
|
if (iframe) {
|
||||||
|
let params = new URLSearchParams(iframe.contentWindow.location.search);
|
||||||
|
let selectedItems = params.getAll('selecteditems');
|
||||||
|
params.delete('selecteditems')
|
||||||
|
this.props.onApplySelectedItems(selectedItems);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resetCollections() {
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
collectionId: null,
|
||||||
|
collectionPage: 1,
|
||||||
|
modalCollections: []
|
||||||
|
});
|
||||||
|
this.fetchModalCollections();
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelSelection() {
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
modalCollections: []
|
||||||
|
});
|
||||||
|
|
||||||
|
this.props.onCancelSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return this.state.collectionId != null && this.state.collectionId != undefined ? (
|
||||||
|
// Items modal
|
||||||
|
<Modal
|
||||||
|
className="wp-block-tainacan-modal dynamic-modal"
|
||||||
|
title={ this.props.loadStrategy == 'selection' ? __('Select items to add on block', 'tainacan') : __('Configure the items search to be used on block', 'tainacan')}
|
||||||
|
onRequestClose={ () => this.cancelSelection() }
|
||||||
|
contentLabel={ this.props.loadStrategy == 'selection' ? __('Select items that will be added on block', 'tainacan') : __('Configure your items search that will load items on block', 'tainacan')}>
|
||||||
|
<iframe
|
||||||
|
id="itemsFrame"
|
||||||
|
src={ this.state.searchURL } />
|
||||||
|
<div className="modal-footer-area">
|
||||||
|
<Button
|
||||||
|
isDefault
|
||||||
|
onClick={ () => { this.resetCollections() }}>
|
||||||
|
{__('Switch collection', 'tainacan')}
|
||||||
|
</Button>
|
||||||
|
{ this.props.loadStrategy == 'selection' ?
|
||||||
|
<Button
|
||||||
|
style={{ marginLeft: 'auto' }}
|
||||||
|
isPrimary
|
||||||
|
onClick={ () => this.applySelectedItems() }>
|
||||||
|
{__('Add the selected items', 'tainacan')}
|
||||||
|
</Button>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
{ this.props.loadStrategy == 'search' ?
|
||||||
|
<Button
|
||||||
|
isPrimary
|
||||||
|
onClick={ () => this.applySelectedSearchURL() }>
|
||||||
|
{__('Use this search', 'tainacan')}
|
||||||
|
</Button>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
) : (
|
||||||
|
// Collections modal
|
||||||
|
<Modal
|
||||||
|
className="wp-block-tainacan-modal"
|
||||||
|
title={__('Select a collection to fetch items from', 'tainacan')}
|
||||||
|
onRequestClose={ () => this.cancelSelection() }
|
||||||
|
contentLabel={__('Select items', 'tainacan')}>
|
||||||
|
<div>
|
||||||
|
<div className="modal-search-area">
|
||||||
|
<TextControl
|
||||||
|
label={__('Search for a collection', 'tainacan')}
|
||||||
|
value={ this.state.searchCollectionName }
|
||||||
|
onChange={(value) => {
|
||||||
|
this.setState({
|
||||||
|
searchCollectionName: value
|
||||||
|
});
|
||||||
|
_.debounce(this.fetchCollections(value), 300);
|
||||||
|
}}/>
|
||||||
|
</div>
|
||||||
|
{(
|
||||||
|
this.state.searchCollectionName != '' ? (
|
||||||
|
this.state.collections.length > 0 ?
|
||||||
|
(
|
||||||
|
<div>
|
||||||
|
<div className="modal-radio-list">
|
||||||
|
{
|
||||||
|
<RadioControl
|
||||||
|
selected={ this.state.temporaryCollectionId }
|
||||||
|
options={
|
||||||
|
this.state.collections.map((collection) => {
|
||||||
|
return { label: collection.name, value: '' + collection.id }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onChange={ ( aCollectionId ) => {
|
||||||
|
this.setState({ temporaryCollectionId: aCollectionId });
|
||||||
|
} } />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) :
|
||||||
|
this.state.isLoadingCollections ? (
|
||||||
|
<Spinner />
|
||||||
|
) :
|
||||||
|
<div className="modal-loadmore-section">
|
||||||
|
<p>{ __('Sorry, no collection found.', 'tainacan') }</p>
|
||||||
|
</div>
|
||||||
|
):
|
||||||
|
this.state.modalCollections.length > 0 ?
|
||||||
|
(
|
||||||
|
<div>
|
||||||
|
<div className="modal-radio-list">
|
||||||
|
{
|
||||||
|
<RadioControl
|
||||||
|
selected={ this.state.temporaryCollectionId }
|
||||||
|
options={
|
||||||
|
this.state.modalCollections.map((collection) => {
|
||||||
|
return { label: collection.name, value: '' + collection.id }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onChange={ ( aCollectionId ) => {
|
||||||
|
this.setState({ temporaryCollectionId: aCollectionId });
|
||||||
|
} } />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div className="modal-loadmore-section">
|
||||||
|
<p>{ __('Showing', 'tainacan') + " " + this.state.modalCollections.length + " " + __('of', 'tainacan') + " " + this.state.totalModalCollections + " " + __('collections', 'tainacan') + "."}</p>
|
||||||
|
{
|
||||||
|
this.state.modalCollections.length < this.state.totalModalCollections ? (
|
||||||
|
<Button
|
||||||
|
isDefault
|
||||||
|
isSmall
|
||||||
|
onClick={ () => this.fetchModalCollections() }>
|
||||||
|
{__('Load more', 'tainacan')}
|
||||||
|
</Button>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : this.state.isLoadingCollections ? <Spinner/> :
|
||||||
|
<div className="modal-loadmore-section">
|
||||||
|
<p>{ __('Sorry, no collection found.', 'tainacan') }</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="modal-footer-area">
|
||||||
|
<Button
|
||||||
|
isDefault
|
||||||
|
onClick={ () => { this.cancelSelection() }}>
|
||||||
|
{__('Cancel', 'tainacan')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
isPrimary
|
||||||
|
disabled={ this.state.temporaryCollectionId == undefined || this.state.temporaryCollectionId == null || this.state.temporaryCollectionId == ''}
|
||||||
|
onClick={ () => { this.selectCollection(this.state.temporaryCollectionId); } }>
|
||||||
|
{ this.props.loadStrategy == 'selection' ? __('Select items', 'tainacan') : __('Configure search', 'tainacan')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,457 @@
|
||||||
|
const { registerBlockType } = wp.blocks;
|
||||||
|
|
||||||
|
const { __ } = wp.i18n;
|
||||||
|
|
||||||
|
const { RangeControl, Spinner, Button, ToggleControl, SelectControl, Placeholder, IconButton, ColorPicker, ColorPalette, BaseControl, PanelBody } = wp.components;
|
||||||
|
|
||||||
|
const { InspectorControls } = wp.editor;
|
||||||
|
|
||||||
|
import CarouselCollectionsModal from './carousel-collections-modal.js';
|
||||||
|
import tainacan from '../../api-client/axios.js';
|
||||||
|
import axios from 'axios';
|
||||||
|
import qs from 'qs';
|
||||||
|
|
||||||
|
registerBlockType('tainacan/carousel-collections-list', {
|
||||||
|
title: __('Tainacan Collections Carousel', 'tainacan'),
|
||||||
|
icon:
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
height="24px"
|
||||||
|
width="24px">
|
||||||
|
<path
|
||||||
|
fill="#298596"
|
||||||
|
d="M18,17v2H12a5.65,5.65,0,0,0-.36-2ZM2,7v7.57a5.74,5.74,0,0,1,2-1.2V7ZM20,6H15L13,4H8A2,2,0,0,0,6,6v7a6,6,0,0,1,5.19,3H20a2,2,0,0,0,2-2V8A2,2,0,0,0,20,6ZM7,16.05v6.06l3.06-3.06ZM5,22.11V16.05L1.94,19.11Z"/>
|
||||||
|
</svg>,
|
||||||
|
category: 'tainacan-blocks',
|
||||||
|
keywords: [ __( 'collections', 'tainacan' ), __( 'carousel', 'tainacan' ), __( 'slider', 'tainacan' ) ],
|
||||||
|
attributes: {
|
||||||
|
content: {
|
||||||
|
type: 'array',
|
||||||
|
source: 'children',
|
||||||
|
selector: 'div'
|
||||||
|
},
|
||||||
|
collectionId: {
|
||||||
|
type: String,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
collections: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
isModalOpen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
selectedCollections: {
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
itemsRequestSource: {
|
||||||
|
type: String,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
maxCollectionsNumber: {
|
||||||
|
type: Number,
|
||||||
|
value: undefined
|
||||||
|
},
|
||||||
|
isLoading: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
isLoadingCollection: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
arrowsPosition: {
|
||||||
|
type: String,
|
||||||
|
value: 'search'
|
||||||
|
},
|
||||||
|
autoPlay: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
autoPlaySpeed: {
|
||||||
|
type: Number,
|
||||||
|
value: 3
|
||||||
|
},
|
||||||
|
loopSlides: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
hideTitle: {
|
||||||
|
type: Boolean,
|
||||||
|
value: true
|
||||||
|
},
|
||||||
|
showCollectionHeader: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
showCollectionLabel: {
|
||||||
|
type: Boolean,
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
collection: {
|
||||||
|
type: Object,
|
||||||
|
value: undefined
|
||||||
|
},
|
||||||
|
blockId: {
|
||||||
|
type: String,
|
||||||
|
default: undefined
|
||||||
|
},
|
||||||
|
collectionBackgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: "#454647"
|
||||||
|
},
|
||||||
|
collectionTextColor: {
|
||||||
|
type: String,
|
||||||
|
default: "#ffffff"
|
||||||
|
},
|
||||||
|
extraParams: {
|
||||||
|
type: Object,
|
||||||
|
default: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
supports: {
|
||||||
|
align: ['full', 'wide'],
|
||||||
|
html: false,
|
||||||
|
multiple: false
|
||||||
|
},
|
||||||
|
edit({ attributes, setAttributes, className, isSelected, clientId }){
|
||||||
|
let {
|
||||||
|
collections,
|
||||||
|
content,
|
||||||
|
collectionId,
|
||||||
|
isModalOpen,
|
||||||
|
itemsRequestSource,
|
||||||
|
selectedCollections,
|
||||||
|
isLoading,
|
||||||
|
arrowsPosition,
|
||||||
|
autoPlay,
|
||||||
|
autoPlaySpeed,
|
||||||
|
loopSlides,
|
||||||
|
hideTitle
|
||||||
|
} = attributes;
|
||||||
|
|
||||||
|
// Obtains block's client id to render it on save function
|
||||||
|
setAttributes({ blockId: clientId });
|
||||||
|
|
||||||
|
function prepareItem(collection) {
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
key={ collection.id }
|
||||||
|
className="collection-list-item">
|
||||||
|
<IconButton
|
||||||
|
onClick={ () => removeItemOfId(collection.id) }
|
||||||
|
icon="no-alt"
|
||||||
|
label={__('Remove', 'tainacan')}/>
|
||||||
|
<a
|
||||||
|
id={ isNaN(collection.id) ? collection.id : 'collection-id-' + collection.id }
|
||||||
|
href={ collection.url }
|
||||||
|
target="_blank">
|
||||||
|
<img
|
||||||
|
src={
|
||||||
|
collection.thumbnail && collection.thumbnail['tainacan-medium'][0] && collection.thumbnail['tainacan-medium'][0]
|
||||||
|
?
|
||||||
|
collection.thumbnail['tainacan-medium'][0]
|
||||||
|
:
|
||||||
|
(collection.thumbnail && collection.thumbnail['thumbnail'][0] && collection.thumbnail['thumbnail'][0]
|
||||||
|
?
|
||||||
|
collection.thumbnail['thumbnail'][0]
|
||||||
|
:
|
||||||
|
`${tainacan_plugin.base_url}/admin/images/placeholder_square.png`)
|
||||||
|
}
|
||||||
|
alt={ collection.title ? collection.title : __( 'Thumbnail', 'tainacan' ) }/>
|
||||||
|
{ !hideTitle ? <span>{ collection.title ? collection.title : '' }</span> : null }
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setContent(){
|
||||||
|
isLoading = true;
|
||||||
|
|
||||||
|
setAttributes({
|
||||||
|
isLoading: isLoading
|
||||||
|
});
|
||||||
|
|
||||||
|
if (itemsRequestSource != undefined && typeof itemsRequestSource == 'function')
|
||||||
|
itemsRequestSource.cancel('Previous collections search canceled.');
|
||||||
|
|
||||||
|
itemsRequestSource = axios.CancelToken.source();
|
||||||
|
|
||||||
|
collections = [];
|
||||||
|
|
||||||
|
let endpoint = '/collection/' + collectionId + '/collections?'+ qs.stringify({ postin: selectedCollections }) + '&fetch_only=title,url,thumbnail';
|
||||||
|
tainacan.get(endpoint, { cancelToken: itemsRequestSource.token })
|
||||||
|
.then(response => {
|
||||||
|
|
||||||
|
for (let collection of response.data.collections)
|
||||||
|
collections.push(prepareItem(collection));
|
||||||
|
|
||||||
|
setAttributes({
|
||||||
|
content: <div></div>,
|
||||||
|
collections: collections,
|
||||||
|
isLoading: false,
|
||||||
|
itemsRequestSource: itemsRequestSource
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function openCarouselModal() {
|
||||||
|
isModalOpen = true;
|
||||||
|
setAttributes( {
|
||||||
|
isModalOpen: isModalOpen
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeItemOfId(itemId) {
|
||||||
|
|
||||||
|
let existingItemIndex = collections.findIndex((existingItem) => existingItem.key == itemId);
|
||||||
|
if (existingItemIndex >= 0)
|
||||||
|
collections.splice(existingItemIndex, 1);
|
||||||
|
|
||||||
|
let existingSelectedItemIndex = selectedCollections.findIndex((existingSelectedItem) => existingSelectedItem == itemId);
|
||||||
|
if (existingSelectedItemIndex >= 0)
|
||||||
|
selectedCollections.splice(existingSelectedItemIndex, 1);
|
||||||
|
|
||||||
|
setAttributes({
|
||||||
|
selectedCollections: selectedCollections,
|
||||||
|
collections: collections,
|
||||||
|
content: <div></div>
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Executed only on the first load of page
|
||||||
|
if(content && content.length && content[0].type)
|
||||||
|
setContent();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<InspectorControls>
|
||||||
|
|
||||||
|
<PanelBody
|
||||||
|
title={__('Carousel', 'tainacan')}
|
||||||
|
initialOpen={ true }
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<ToggleControl
|
||||||
|
label={__('Hide title', 'tainacan')}
|
||||||
|
help={ !hideTitle ? __('Toggle to hide collection\'s title', 'tainacan') : __('Do not hide collection\'s title', 'tainacan')}
|
||||||
|
checked={ hideTitle }
|
||||||
|
onChange={ ( isChecked ) => {
|
||||||
|
hideTitle = isChecked;
|
||||||
|
setAttributes({ hideTitle: hideTitle });
|
||||||
|
setContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ToggleControl
|
||||||
|
label={__('Loop slides', 'tainacan')}
|
||||||
|
help={ !loopSlides ? __('Toggle to make slides loop from first to last', 'tainacan') : __('Do not loop slides from first to last', 'tainacan')}
|
||||||
|
checked={ loopSlides }
|
||||||
|
onChange={ ( isChecked ) => {
|
||||||
|
loopSlides = isChecked;
|
||||||
|
setAttributes({ loopSlides: loopSlides });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<ToggleControl
|
||||||
|
label={__('Auto play', 'tainacan')}
|
||||||
|
help={ !autoPlay ? __('Toggle to automatically slide to next collection', 'tainacan') : __('Do not automatically slide to next collection', 'tainacan')}
|
||||||
|
checked={ autoPlay }
|
||||||
|
onChange={ ( isChecked ) => {
|
||||||
|
autoPlay = isChecked;
|
||||||
|
setAttributes({ autoPlay: autoPlay });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
autoPlay ?
|
||||||
|
<RangeControl
|
||||||
|
label={__('Seconds before translating to next', 'tainacan')}
|
||||||
|
value={ autoPlaySpeed }
|
||||||
|
onChange={ ( aAutoPlaySpeed ) => {
|
||||||
|
autoPlaySpeed = aAutoPlaySpeed;
|
||||||
|
setAttributes( { autoPlaySpeed: aAutoPlaySpeed } )
|
||||||
|
}}
|
||||||
|
min={ 1 }
|
||||||
|
max={ 5 }
|
||||||
|
/>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
<SelectControl
|
||||||
|
label={__('Arrows', 'tainacan')}
|
||||||
|
value={ arrowsPosition }
|
||||||
|
options={ [
|
||||||
|
{ label: __('Around', 'tainacan'), value: 'around' },
|
||||||
|
{ label: __('Left', 'tainacan'), value: 'left' },
|
||||||
|
{ label: __('Right', 'tainacan'), value: 'right' }
|
||||||
|
] }
|
||||||
|
onChange={ ( aPosition ) => {
|
||||||
|
arrowsPosition = aPosition;
|
||||||
|
|
||||||
|
setAttributes({ arrowsPosition: arrowsPosition });
|
||||||
|
}}/>
|
||||||
|
</div>
|
||||||
|
</PanelBody>
|
||||||
|
</InspectorControls>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{ isSelected ?
|
||||||
|
(
|
||||||
|
<div>
|
||||||
|
{ isModalOpen ?
|
||||||
|
<CarouselCollectionsModal
|
||||||
|
onApplySelectedCollections={ (aSelectionOfCollections) => {
|
||||||
|
selectedCollections = selectedCollections.concat(aSelectionOfCollections);
|
||||||
|
setAttributes({
|
||||||
|
selectedCollections: selectedCollections,
|
||||||
|
isModalOpen: false
|
||||||
|
});
|
||||||
|
setContent();
|
||||||
|
}}
|
||||||
|
onCancelSelection={ () => setAttributes({ isModalOpen: false }) }/>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
|
||||||
|
{ collections.length ? (
|
||||||
|
<div className="block-control">
|
||||||
|
<p>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
height="24px"
|
||||||
|
width="24px">
|
||||||
|
<path d="M18,17v2H12a5.65,5.65,0,0,0-.36-2ZM2,7v7.57a5.74,5.74,0,0,1,2-1.2V7ZM20,6H15L13,4H8A2,2,0,0,0,6,6v7a6,6,0,0,1,5.19,3H20a2,2,0,0,0,2-2V8A2,2,0,0,0,20,6ZM7,16.05v6.06l3.06-3.06ZM5,22.11V16.05L1.94,19.11Z"/>
|
||||||
|
</svg>
|
||||||
|
{__('List collections on a Carousel', 'tainacan')}
|
||||||
|
</p>
|
||||||
|
<Button
|
||||||
|
isPrimary
|
||||||
|
type="submit"
|
||||||
|
onClick={ () => openCarouselModal() }>
|
||||||
|
{__('Add more collections', 'tainacan')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
): null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
{ !collections.length && !isLoading ? (
|
||||||
|
<Placeholder
|
||||||
|
icon={(
|
||||||
|
<img
|
||||||
|
width={148}
|
||||||
|
src={ `${tainacan_plugin.base_url}/admin/images/tainacan_logo_header.svg` }
|
||||||
|
alt="Tainacan Logo"/>
|
||||||
|
)}>
|
||||||
|
<p>
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
height="24px"
|
||||||
|
width="24px">
|
||||||
|
<path d="M18,17v2H12a5.65,5.65,0,0,0-.36-2ZM2,7v7.57a5.74,5.74,0,0,1,2-1.2V7ZM20,6H15L13,4H8A2,2,0,0,0,6,6v7a6,6,0,0,1,5.19,3H20a2,2,0,0,0,2-2V8A2,2,0,0,0,20,6ZM7,16.05v6.06l3.06-3.06ZM5,22.11V16.05L1.94,19.11Z"/>
|
||||||
|
</svg>
|
||||||
|
{__('List collections on a Carousel, using search or collection selection.', 'tainacan')}
|
||||||
|
</p>
|
||||||
|
<Button
|
||||||
|
isPrimary
|
||||||
|
type="submit"
|
||||||
|
onClick={ () => openCarouselModal() }>
|
||||||
|
{__('Select Collections', 'tainacan')}
|
||||||
|
</Button>
|
||||||
|
</Placeholder>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
{ isLoading ?
|
||||||
|
<div class="spinner-container">
|
||||||
|
<Spinner />
|
||||||
|
</div> :
|
||||||
|
<div>
|
||||||
|
{ isSelected && collections.length ?
|
||||||
|
<div class="preview-warning">{__('Warning: this is just a demonstration. To see the carousel in action, either preview or publish your post.', 'tainacan')}</div>
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
{ collections.length ? (
|
||||||
|
<div
|
||||||
|
className={'collections-list-edit-container has-arrows-' + arrowsPosition}>
|
||||||
|
<button
|
||||||
|
class="swiper-button-prev"
|
||||||
|
slot="button-prev"
|
||||||
|
style={{ cursor: 'not-allowed' }}>
|
||||||
|
<svg
|
||||||
|
width="42"
|
||||||
|
height="42"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
|
||||||
|
<path
|
||||||
|
d="M0 0h24v24H0z"
|
||||||
|
fill="none"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<ul className={'collections-list-edit'}>
|
||||||
|
{ collections }
|
||||||
|
</ul>
|
||||||
|
<button
|
||||||
|
class="swiper-button-next"
|
||||||
|
slot="button-next"
|
||||||
|
style={{ cursor: 'not-allowed' }}>
|
||||||
|
<svg
|
||||||
|
width="42"
|
||||||
|
height="42"
|
||||||
|
viewBox="0 0 24 24">
|
||||||
|
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
|
||||||
|
<path
|
||||||
|
d="M0 0h24v24H0z"
|
||||||
|
fill="none"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
):null
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
save({ attributes, className }){
|
||||||
|
const {
|
||||||
|
content,
|
||||||
|
blockId,
|
||||||
|
collectionId,
|
||||||
|
selectedCollections,
|
||||||
|
arrowsPosition,
|
||||||
|
maxCollectionsNumber,
|
||||||
|
autoPlay,
|
||||||
|
autoPlaySpeed,
|
||||||
|
loopSlides,
|
||||||
|
hideTitle,
|
||||||
|
extraParams
|
||||||
|
} = attributes;
|
||||||
|
return <div
|
||||||
|
className={ className }
|
||||||
|
selected-collections={ JSON.stringify(selectedCollections) }
|
||||||
|
arrows-position={ arrowsPosition }
|
||||||
|
collection-id={ collectionId }
|
||||||
|
auto-play={ '' + autoPlay }
|
||||||
|
auto-play-speed={ autoPlaySpeed }
|
||||||
|
loop-slides={ '' + loopSlides }
|
||||||
|
hide-title={ '' + hideTitle }
|
||||||
|
max-collections-number={ maxCollectionsNumber }
|
||||||
|
tainacan-api-root={ tainacan_plugin.root }
|
||||||
|
tainacan-base-url={ tainacan_plugin.base_url }
|
||||||
|
extraParams={ JSON.stringify(extraParams) }
|
||||||
|
id={ 'wp-block-tainacan-carousel-collections-list_' + blockId }>
|
||||||
|
{ content }
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
});
|
|
@ -17,6 +17,8 @@ module.exports = {
|
||||||
gutenberg_carousel_items_list: './src/gutenberg-blocks/tainacan-items/carousel-items-list/index.js',
|
gutenberg_carousel_items_list: './src/gutenberg-blocks/tainacan-items/carousel-items-list/index.js',
|
||||||
gutenberg_carousel_items_list_theme: './src/gutenberg-blocks/tainacan-items/carousel-items-list/carousel-items-list-theme.js',
|
gutenberg_carousel_items_list_theme: './src/gutenberg-blocks/tainacan-items/carousel-items-list/carousel-items-list-theme.js',
|
||||||
gutenberg_collections_list: './src/gutenberg-blocks/tainacan-collections/collections-list/index.js',
|
gutenberg_collections_list: './src/gutenberg-blocks/tainacan-collections/collections-list/index.js',
|
||||||
|
gutenberg_carousel_collections_list: './src/gutenberg-blocks/tainacan-collections/carousel-collections-list/index.js',
|
||||||
|
gutenberg_carousel_collections_list_theme: './src/gutenberg-blocks/tainacan-collections/carousel-collections-list/carousel-collections-list-theme.js',
|
||||||
gutenberg_facets_list: './src/gutenberg-blocks/tainacan-facets/facets-list/index.js',
|
gutenberg_facets_list: './src/gutenberg-blocks/tainacan-facets/facets-list/index.js',
|
||||||
gutenberg_facets_list_theme: './src/gutenberg-blocks/tainacan-facets/facets-list/facets-list-theme.js'
|
gutenberg_facets_list_theme: './src/gutenberg-blocks/tainacan-facets/facets-list/facets-list-theme.js'
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue