Continues refactor for block.json strategy #580

This commit is contained in:
mateuswetah 2021-07-15 14:25:43 -03:00
parent 4115e40d57
commit 6cb63649f4
19 changed files with 2045 additions and 1682 deletions

View File

@ -318,7 +318,9 @@
display: -ms-grid;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 50% 50%; }
grid-template-rows: 1fr 1fr;
grid-gap: 5px;
gap: 5px; }
.wp-block-tainacan-carousel-terms-list ul.terms-list-edit li.term-list-item .term-items-grid img:first-of-type {
flex-basis: 100%;
-ms-grid-column: 1;
@ -329,7 +331,6 @@
grid-row: 1/3; }
.wp-block-tainacan-carousel-terms-list ul.terms-list-edit li.term-list-item .term-items-grid img {
flex-basis: 50%;
padding: 2px;
margin-bottom: 0px; }
.wp-block-tainacan-carousel-terms-list ul.terms-list-edit li.terms-list-item {
width: calc(20% - 32px);

File diff suppressed because one or more lines are too long

View File

@ -229,7 +229,7 @@ function tainacan_blocks_register_block($block_slug, $options = []) {
if (function_exists('register_block_type')) {
if (
version_compare( $wp_version, '5.8-RC', '>=') &&
($block_slug == 'carousel-collections-list' || $block_slug == 'collections-list' || $block_slug == 'carousel-items-list')
($block_slug == 'carousel-collections-list' || $block_slug == 'collections-list' || $block_slug == 'carousel-items-list' || $block_slug == 'carousel-terms-list' || $block_slug == 'dynamic-items-list')
)
register_block_type( __DIR__ . '/tainacan-blocks/' . $block_slug );
else

View File

@ -44,7 +44,7 @@ export default class CarouselItemsModal extends React.Component {
collectionId: this.props.existingCollectionId
});
if (this.props.existingCollectionId != null && this.props.existingCollectionId != undefined) {
if (this.props.existingCollectionId) {
this.fetchCollection(this.props.existingCollectionId);
this.setState({
searchURL: this.props.existingSearchURL ? this.props.existingSearchURL : tainacan_blocks.admin_url + 'admin.php?page=tainacan_admin#/collections/'+ this.props.existingCollectionId + (this.props.loadStrategy == 'search' ? '/items/?iframemode=true&readmode=true&status=publish' : '/items/?iframemode=true&status=publish') });
@ -116,7 +116,8 @@ export default class CarouselItemsModal extends React.Component {
collectionId: selectedCollectionId,
searchURL: tainacan_blocks.admin_url + 'admin.php?page=tainacan_admin#/collections/' + selectedCollectionId + (this.props.loadStrategy == 'search' ? '/items/?iframemode=true&readmode=true&status=publish' : '/items/?iframemode=true&status=publish')
});
console.log(selectedCollectionId)
console.log(tainacan_blocks.admin_url + 'admin.php?page=tainacan_admin#/collections/' + selectedCollectionId + (this.props.loadStrategy == 'search' ? '/items/?iframemode=true&readmode=true&status=publish' : '/items/?iframemode=true&status=publish'));
this.props.onSelectCollection(selectedCollectionId);
this.fetchCollection(selectedCollectionId);
}
@ -201,7 +202,7 @@ export default class CarouselItemsModal extends React.Component {
}
render() {
return this.state.collectionId != null && this.state.collectionId != undefined ? (
return this.state.collectionId ? (
// Items modal
<Modal
className="wp-block-tainacan-modal dynamic-modal"

View File

@ -0,0 +1,111 @@
{
"name": "tainacan/carousel-terms-list",
"title": "Tainacan Terms Carousel",
"category": "tainacan-blocks",
"keywords": [ "carousel", "slider", "taxonomy" ],
"description": "List terms on a Carousel, showing their thumbnails or a preview of items.",
"example": {
"attributes": {
"content": "preview"
}
},
"attributes": {
"content": {
"type": "Array",
"source": "children",
"selector": "div"
},
"terms": {
"type": "Array",
"default": []
},
"isModalOpen": {
"type": "Boolean",
"default": false
},
"selectedTerms": {
"type": "Array",
"default": []
},
"itemsRequestSource": {
"type": "String",
"default": ""
},
"maxTermsNumber": {
"type": "Number",
"value": 12
},
"maxTermsPerScreen": {
"type": "Number",
"value": 6
},
"isLoading": {
"type": "Boolean",
"value": false
},
"isLoadingTerm": {
"type": "Boolean",
"value": false
},
"arrowsPosition": {
"type": "String",
"value": "around"
},
"largeArrows": {
"type": "Boolean",
"value": false
},
"autoPlay": {
"type": "Boolean",
"value": false
},
"autoPlaySpeed": {
"type": "Number",
"value": 3
},
"loopSlides": {
"type": "Boolean",
"value": false
},
"hideName": {
"type": "Boolean",
"value": true
},
"showTermThumbnail": {
"type": "Boolean",
"value": false
},
"term": {
"type": "Object",
"value": {}
},
"blockId": {
"type": "String",
"default": ""
},
"termBackgroundColor": {
"type": "String",
"default": "#454647"
},
"termTextColor": {
"type": "String",
"default": "#ffffff"
},
"taxonomyId": {
"type": "String",
"default": ""
}
},
"supports": {
"align": ["full", "wide"],
"html": false,
"multiple": true,
"typography": {
"fontSize": true
}
},
"editorScript": "carousel-terms-list",
"script": "carousel-terms-list-theme",
"editorStyle": "carousel-terms-list",
"style": "carousel-terms-list"
}

View File

@ -1,4 +1,135 @@
export default [
/* Deprecated on Tainacan 0.18.4 due to the new block.json strategy */
{
attributes: {
content: {
type: 'array',
source: 'children',
selector: 'div'
},
terms: {
type: Array,
default: []
},
isModalOpen: {
type: Boolean,
default: false
},
selectedTerms: {
type: Array,
default: []
},
itemsRequestSource: {
type: String,
default: undefined
},
maxTermsNumber: {
type: Number,
value: undefined
},
maxTermsPerScreen: {
type: Number,
value: 6
},
isLoading: {
type: Boolean,
value: false
},
isLoadingTerm: {
type: Boolean,
value: false
},
arrowsPosition: {
type: String,
value: 'search'
},
largeArrows: {
type: Boolean,
value: false
},
autoPlay: {
type: Boolean,
value: false
},
autoPlaySpeed: {
type: Number,
value: 3
},
loopSlides: {
type: Boolean,
value: false
},
hideName: {
type: Boolean,
value: true
},
showTermThumbnail: {
type: Boolean,
value: false
},
term: {
type: Object,
value: undefined
},
blockId: {
type: String,
default: undefined
},
termBackgroundColor: {
type: String,
default: "#454647"
},
termTextColor: {
type: String,
default: "#ffffff"
},
taxonomyId: {
type: String,
default: undefined
}
},
supports: {
align: ['full', 'wide'],
html: false,
multiple: true,
fontSize: true
},
save({ attributes, className }){
const {
content,
blockId,
selectedTerms,
arrowsPosition,
largeArrows,
maxTermsPerScreen,
maxTermsNumber,
autoPlay,
autoPlaySpeed,
loopSlides,
hideName,
showTermThumbnail,
taxonomyId
} = attributes;
return <div
className={ className }
selected-terms={ JSON.stringify(selectedTerms.map((term) => { return term.id; })) }
arrows-position={ arrowsPosition }
auto-play={ '' + autoPlay }
auto-play-speed={ autoPlaySpeed }
loop-slides={ '' + loopSlides }
hide-name={ '' + hideName }
large-arrows={ '' + largeArrows }
max-terms-number={ maxTermsNumber }
max-terms-per-screen={ maxTermsPerScreen }
taxonomy-id={ taxonomyId }
tainacan-api-root={ tainacan_blocks.root }
tainacan-base-url={ tainacan_blocks.base_url }
show-term-thumbnail={ '' + showTermThumbnail }
id={ 'wp-block-tainacan-carousel-terms-list_' + blockId }>
{ content }
</div>
}
},
/* Deprecated on Tainacan 0.17.2, due to the introduction of support: fontSize */
{
attributes: {

View File

@ -0,0 +1,429 @@
const { __ } = wp.i18n;
const { RangeControl, Spinner, Button, BaseControl, ToggleControl, SelectControl, Placeholder, IconButton, PanelBody } = wp.components;
const { InspectorControls, BlockControls } = ( tainacan_blocks.wp_version < '5.2' ? wp.editor : wp.blockEditor );
import TermsModal from '../terms-list/terms-modal.js';
import tainacan from '../../js/axios.js';
import axios from 'axios';
import qs from 'qs';
import { ThumbnailHelperFunctions } from '../../../admin/js/utilities.js';
import TainacanBlocksCompatToolbar from '../../js/tainacan-blocks-compat-toolbar.js';
import 'swiper/css/swiper.min.css';
export default function({ attributes, setAttributes, className, isSelected, clientId }){
let {
terms,
content,
isModalOpen,
itemsRequestSource,
selectedTerms,
isLoading,
largeArrows,
maxTermsPerScreen,
arrowsPosition,
autoPlay,
autoPlaySpeed,
loopSlides,
hideName,
showTermThumbnail,
taxonomyId
} = attributes;
// Obtains block's client id to render it on save function
setAttributes({ blockId: clientId });
// Sets some defaults that were not working
if (maxTermsPerScreen === undefined) {
maxTermsPerScreen = 6;
setAttributes({ maxTermsPerScreen: maxTermsPerScreen });
}
const thumbHelper = ThumbnailHelperFunctions();
function prepareItem(term, termItems) {
return (
<li
key={ term.id }
className={ 'term-list-item ' + (!showTermThumbnail ? 'term-list-item-grid ' : '') + (maxTermsPerScreen ? ' max-terms-per-screen-' + maxTermsPerScreen : '') }>
{ tainacan_blocks.wp_version < '5.4' ?
<IconButton
onClick={ () => removeItemOfId(term.id) }
icon="no-alt"
label={__('Remove', 'tainacan')}/>
:
<Button
onClick={ () => removeItemOfId(term.id) }
icon="no-alt"
label={__('Remove', 'tainacan')}/>
}
<a
id={ isNaN(term.id) ? term.id : 'term-id-' + term.id }
href={ term.url }
target="_blank">
{ !showTermThumbnail ?
<div class="term-items-grid">
<img
src={ termItems[0] ? thumbHelper.getSrc(termItems[0]['thumbnail'], 'tainacan-medium', termItems[0]['document_mimetype']) :`${tainacan_blocks.base_url}/assets/images/placeholder_square.png` }
srcSet={ termItems[0] ? thumbHelper.getSrcSet(termItems[0]['thumbnail'], 'tainacan-medium', termItems[0]['document_mimetype']) :`${tainacan_blocks.base_url}/assets/images/placeholder_square.png` }
alt={ termItems[0] && termItems[0].thumbnail_alt ? termItems[0].thumbnail_alt : (termItems[0] && termItems[0].name ? termItems[0].name : __( 'Thumbnail', 'tainacan' )) } />
<img
src={ termItems[1] ? thumbHelper.getSrc(termItems[1]['thumbnail'], 'tainacan-medium', termItems[1]['document_mimetype']) :`${tainacan_blocks.base_url}/assets/images/placeholder_square.png` }
srcSet={ termItems[1] ? thumbHelper.getSrcSet(termItems[1]['thumbnail'], 'tainacan-medium', termItems[1]['document_mimetype']) :`${tainacan_blocks.base_url}/assets/images/placeholder_square.png` }
alt={ termItems[1] && termItems[1].thumbnail_alt ? termItems[1].thumbnail_alt : (termItems[1] && termItems[1].name ? termItems[1].name : __( 'Thumbnail', 'tainacan' )) } />
<img
src={ termItems[2] ? thumbHelper.getSrc(termItems[2]['thumbnail'], 'tainacan-medium', termItems[2]['document_mimetype']) :`${tainacan_blocks.base_url}/assets/images/placeholder_square.png` }
srcSet={ termItems[2] ? thumbHelper.getSrcSet(termItems[2]['thumbnail'], 'tainacan-medium', termItems[2]['document_mimetype']) :`${tainacan_blocks.base_url}/assets/images/placeholder_square.png` }
alt={ termItems[2] && termItems[2].thumbnail_alt ? termItems[2].thumbnail_alt : (termItems[2] && termItems[2].name ? termItems[2].name : __( 'Thumbnail', 'tainacan' )) } />
</div>
:
<img
src={ term.header_image ? term.header_image : `${tainacan_blocks.base_url}/assets/images/placeholder_square.png`}
alt={ term.name ? term.name : __( 'Thumbnail', 'tainacan' )}/>
}
{ !hideName ? <span>{ term.name ? term.name : '' }</span> : null }
</a>
</li>
);
}
function setContent(){
isLoading = true;
setAttributes({
isLoading: isLoading
});
if (itemsRequestSource != undefined && typeof itemsRequestSource == 'function')
itemsRequestSource.cancel('Previous terms search canceled.');
itemsRequestSource = axios.CancelToken.source();
terms = [];
let endpoint = '/taxonomy/' + taxonomyId + '/terms/?'+ qs.stringify({ hideempty: 0, include: selectedTerms.map((term) => { return term.id; }) }) + '&order=asc&fetch_only=id,name,url,header_image';
tainacan.get(endpoint, { cancelToken: itemsRequestSource.token })
.then(response => {
if (showTermThumbnail) {
for (let term of response.data) {
terms.push(prepareItem(term));
}
setAttributes({
content: <div></div>,
terms: terms,
isLoading: false,
itemsRequestSource: itemsRequestSource
});
} else {
let promises = [];
for (let term of response.data) {
promises.push(
tainacan.get('/items/?perpage=3&fetch_only=name,url,thumbnail&taxquery[0][taxonomy]=tnc_tax_' + taxonomyId + '&taxquery[0][terms][0]=' + term.id + '&taxquery[0][compare]=IN')
.then(response => { return({ term: term, termItems: response.data.items }) })
.catch((error) => console.log(error))
);
}
axios.all(promises).then((results) => {
for (let result of results) {
terms.push(prepareItem(result.term, result.termItems));
}
setAttributes({
content: <div></div>,
terms: terms,
isLoading: false,
itemsRequestSource: itemsRequestSource
});
})
}
});
}
function openCarouselModal() {
isModalOpen = true;
setAttributes( {
isModalOpen: isModalOpen
} );
}
function removeItemOfId(itemId) {
let existingItemIndex = terms.findIndex((existingItem) => existingItem.key == itemId);
if (existingItemIndex >= 0)
terms.splice(existingItemIndex, 1);
let existingSelectedItemIndex = selectedTerms.findIndex((existingSelectedItem) => existingSelectedItem.id == itemId);
if (existingSelectedItemIndex >= 0)
selectedTerms.splice(existingSelectedItemIndex, 1);
setAttributes({
selectedTerms: selectedTerms,
terms: terms,
content: <div></div>
});
}
// Executed only on the first load of page
if(content && content.length && content[0].type)
setContent();
return content == 'preview' ?
<div className={className}>
<img
width="100%"
src={ `${tainacan_blocks.base_url}/assets/images/carousel-terms-list.png` } />
</div>
: (
<div className={className}>
{ terms.length ?
<BlockControls>
{
TainacanBlocksCompatToolbar({
label: __('Add more terms', 'tainacan'),
icon: <svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -2 24 24"
height="24px"
width="24px">
<path d="M21.43,14.64,19.32,17a2.57,2.57,0,0,1-2,1H12.05a6,6,0,0,0-6-6H6V10.64A2.59,2.59,0,0,1,8.59,8H17.3a2.57,2.57,0,0,1,2,1l2.11,2.38A2.59,2.59,0,0,1,21.43,14.64ZM4,4A2,2,0,0,0,2,6v7.63a5.74,5.74,0,0,1,2-1.2V6H16V4ZM7,15.05v6.06l3.06-3.06ZM5,21.11V15.05L1.94,18.11Z"/>
</svg>,
onClick: openCarouselModal
})
}
</BlockControls>
: null }
<div>
<InspectorControls>
<PanelBody
title={__('Carousel', 'tainacan')}
initialOpen={ true }
>
<BaseControl
id="term-carousel-view-modes"
label={ __('Term layout', 'tainacan')}>
<div className="term-carousel-view-modes">
<button
onClick={ () => {
showTermThumbnail = false;
setAttributes({ showTermThumbnail: showTermThumbnail });
setContent();
}
}
className={'term-carousel-view-mode-grid' + (showTermThumbnail ? '' : ' is-active')}>
<div>
<div />
<div />
<div />
</div>
<label>{ __('Items\'s grid', 'tainacan') }</label>
</button>
<button
onClick={ () => {
showTermThumbnail = true;
setAttributes({ showTermThumbnail: showTermThumbnail });
setContent();
}
}
className={'term-carousel-view-mode-thumbnail' + (showTermThumbnail ? ' is-active' : '')}>
<div />
<label>{ __('Thumbnail', 'tainacan') }</label>
</button>
</div>
</BaseControl>
<RangeControl
label={ __('Maximum terms per slide on a wide screen', 'tainacan') }
help={ (showTermThumbnail && maxTermsPerScreen <= 3) ? __('Warning: with such a small number of terms per slide, the image size is greater and might be pixelated.', 'tainacan') : null }
value={ maxTermsPerScreen ? maxTermsPerScreen : 6 }
onChange={ ( aMaxTermsPerScreen ) => {
maxTermsPerScreen = aMaxTermsPerScreen;
setAttributes( { maxTermsPerScreen: aMaxTermsPerScreen } );
setContent();
}}
min={ 1 }
max={ 9 }
/>
<ToggleControl
label={__('Hide name', 'tainacan')}
help={ !hideName ? __('Toggle to hide term\'s name', 'tainacan') : __('Do not hide term\'s name', 'tainacan')}
checked={ hideName }
onChange={ ( isChecked ) => {
hideName = isChecked;
setAttributes({ hideName: hideName });
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 term', 'tainacan') : __('Do not automatically slide to next term', 'tainacan')}
checked={ autoPlay }
onChange={ ( isChecked ) => {
autoPlay = isChecked;
setAttributes({ autoPlay: autoPlay });
}
}
/>
{
autoPlay ?
<RangeControl
label={__('Seconds before translating to next', 'tainacan')}
value={ autoPlaySpeed ? autoPlaySpeed : 3 }
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 });
}}/>
<ToggleControl
label={__('Large arrows', 'tainacan')}
help={ !largeArrows ? __('Toggle to display arrows bigger than the default size.', 'tainacan') : __('Do not show arrows bigger than the default size.', 'tainacan')}
checked={ largeArrows }
onChange={ ( isChecked ) => {
largeArrows = isChecked;
setAttributes({ largeArrows: largeArrows });
}
}
/>
</PanelBody>
</InspectorControls>
</div>
{ isSelected ?
(
<div>
{ isModalOpen ?
<TermsModal
replaceTermId={ false } // The Terms modal adds `term-id-` string to terms ids. Here we dont' need it
existingTaxonomyId={ taxonomyId }
selectedTermsObject={ selectedTerms }
onSelectTaxonomy={ (selectedTaxonomyId) => {
taxonomyId = selectedTaxonomyId;
setAttributes({ taxonomyId: taxonomyId });
}}
onApplySelection={ (aSelectionOfTerms) =>{
selectedTerms = aSelectionOfTerms;
setAttributes({
selectedTerms: selectedTerms,
isModalOpen: false
});
setContent();
}}
onCancelSelection={ () => setAttributes({ isModalOpen: false }) }/>
: null
}
</div>
) : null
}
{ !terms.length && !isLoading ? (
<Placeholder
className="tainacan-block-placeholder"
icon={(
<img
width={148}
src={ `${tainacan_blocks.base_url}/assets/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="M21.43,14.64,19.32,17a2.57,2.57,0,0,1-2,1H12.05a6,6,0,0,0-6-6H6V10.64A2.59,2.59,0,0,1,8.59,8H17.3a2.57,2.57,0,0,1,2,1l2.11,2.38A2.59,2.59,0,0,1,21.43,14.64ZM4,4A2,2,0,0,0,2,6v7.63a5.74,5.74,0,0,1,2-1.2V6H16V4ZM7,15.05v6.06l3.06-3.06ZM5,21.11V15.05L1.94,18.11Z"/>
</svg>
{__('List terms on a Carousel, showing their thumbnails or a preview of items.', 'tainacan')}
</p>
<Button
isPrimary
type="button"
onClick={ () => openCarouselModal() }>
{__('Select Terms', 'tainacan')}
</Button>
</Placeholder>
) : null
}
{ isLoading ?
<div class="spinner-container">
<Spinner />
</div> :
<div>
{ isSelected && terms.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
}
{ terms.length ? (
<div
className={'terms-list-edit-container ' + (arrowsPosition ? 'has-arrows-' + arrowsPosition : '') + (largeArrows ? ' has-large-arrows' : '') }>
<button
class="swiper-button-prev"
slot="button-prev"
style={{ cursor: 'not-allowed' }}>
<svg
width={ largeArrows ? 60 : 42 }
height={ largeArrows ? 60 : 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={'terms-list-edit'}>
{ terms }
</ul>
<button
class="swiper-button-next"
slot="button-next"
style={{ cursor: 'not-allowed' }}>
<svg
width={ largeArrows ? 60 : 42 }
height={ largeArrows ? 60 : 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>
);
};

View File

@ -0,0 +1,14 @@
const { SVG, Path } = wp.components;
export default (
<SVG
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
height="24px"
width="24px">
<Path
fill="#298596"
d="M21.43,14.64,19.32,17a2.57,2.57,0,0,1-2,1H12.05a6,6,0,0,0-6-6H6V10.64A2.59,2.59,0,0,1,8.59,8H17.3a2.57,2.57,0,0,1,2,1l2.11,2.38A2.59,2.59,0,0,1,21.43,14.64ZM4,4A2,2,0,0,0,2,6v7.63a5.74,5.74,0,0,1,2-1.2V6H16V4ZM7,15.05v6.06l3.06-3.06ZM5,21.11V15.05L1.94,18.11Z"/>
</SVG>
);

View File

@ -1,582 +1,15 @@
const { registerBlockType } = wp.blocks;
import tainacanRegisterBlockType from '../../js/tainacan-blocks-compat-register.js';
const { __ } = wp.i18n;
import metadata from './block.json';
import icon from './icon.js';
import edit from './edit.js';
import save from './save.js';
import deprecated from './deprecated.js';
const { RangeControl, Spinner, Button, BaseControl, ToggleControl, SelectControl, Placeholder, IconButton, PanelBody } = wp.components;
const { InspectorControls, BlockControls } = ( tainacan_blocks.wp_version < '5.2' ? wp.editor : wp.blockEditor );
import TermsModal from '../terms-list/terms-modal.js';
import tainacan from '../../js/axios.js';
import axios from 'axios';
import qs from 'qs';
import { ThumbnailHelperFunctions } from '../../../admin/js/utilities.js';
import TainacanBlocksCompatToolbar from '../../js/tainacan-blocks-compat-toolbar.js';
import DeprecatedBlocks from './carousel-terms-list-deprecated.js';
import 'swiper/css/swiper.min.css';
registerBlockType('tainacan/carousel-terms-list', {
title: __('Tainacan Terms Carousel', 'tainacan'),
icon:
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
height="24px"
width="24px">
<path
fill="#298596"
d="M21.43,14.64,19.32,17a2.57,2.57,0,0,1-2,1H12.05a6,6,0,0,0-6-6H6V10.64A2.59,2.59,0,0,1,8.59,8H17.3a2.57,2.57,0,0,1,2,1l2.11,2.38A2.59,2.59,0,0,1,21.43,14.64ZM4,4A2,2,0,0,0,2,6v7.63a5.74,5.74,0,0,1,2-1.2V6H16V4ZM7,15.05v6.06l3.06-3.06ZM5,21.11V15.05L1.94,18.11Z"/>
</svg>,
category: 'tainacan-blocks',
keywords: [ __( 'carousel', 'tainacan' ), __( 'slider', 'tainacan' ), __( 'taxonomy', 'tainacan' ) ],
description: __('List terms on a Carousel, showing their thumbnails or a preview of items.', 'tainacan'),
example: {
attributes: {
content: 'preview'
}
},
attributes: {
content: {
type: 'array',
source: 'children',
selector: 'div'
},
terms: {
type: Array,
default: []
},
isModalOpen: {
type: Boolean,
default: false
},
selectedTerms: {
type: Array,
default: []
},
itemsRequestSource: {
type: String,
default: undefined
},
maxTermsNumber: {
type: Number,
value: undefined
},
maxTermsPerScreen: {
type: Number,
value: 6
},
isLoading: {
type: Boolean,
value: false
},
isLoadingTerm: {
type: Boolean,
value: false
},
arrowsPosition: {
type: String,
value: 'search'
},
largeArrows: {
type: Boolean,
value: false
},
autoPlay: {
type: Boolean,
value: false
},
autoPlaySpeed: {
type: Number,
value: 3
},
loopSlides: {
type: Boolean,
value: false
},
hideName: {
type: Boolean,
value: true
},
showTermThumbnail: {
type: Boolean,
value: false
},
term: {
type: Object,
value: undefined
},
blockId: {
type: String,
default: undefined
},
termBackgroundColor: {
type: String,
default: "#454647"
},
termTextColor: {
type: String,
default: "#ffffff"
},
taxonomyId: {
type: String,
default: undefined
}
},
supports: {
align: ['full', 'wide'],
html: false,
multiple: true,
fontSize: true
},
edit({ attributes, setAttributes, className, isSelected, clientId }){
let {
terms,
content,
isModalOpen,
itemsRequestSource,
selectedTerms,
isLoading,
largeArrows,
maxTermsPerScreen,
arrowsPosition,
autoPlay,
autoPlaySpeed,
loopSlides,
hideName,
showTermThumbnail,
taxonomyId
} = attributes;
// Obtains block's client id to render it on save function
setAttributes({ blockId: clientId });
// Sets some defaults that were not working
if (maxTermsPerScreen === undefined) {
maxTermsPerScreen = 6;
setAttributes({ maxTermsPerScreen: maxTermsPerScreen });
}
const thumbHelper = ThumbnailHelperFunctions();
function prepareItem(term, termItems) {
return (
<li
key={ term.id }
className={ 'term-list-item ' + (!showTermThumbnail ? 'term-list-item-grid ' : '') + (maxTermsPerScreen ? ' max-terms-per-screen-' + maxTermsPerScreen : '') }>
{ tainacan_blocks.wp_version < '5.4' ?
<IconButton
onClick={ () => removeItemOfId(term.id) }
icon="no-alt"
label={__('Remove', 'tainacan')}/>
:
<Button
onClick={ () => removeItemOfId(term.id) }
icon="no-alt"
label={__('Remove', 'tainacan')}/>
}
<a
id={ isNaN(term.id) ? term.id : 'term-id-' + term.id }
href={ term.url }
target="_blank">
{ !showTermThumbnail ?
<div class="term-items-grid">
<img
src={ termItems[0] ? thumbHelper.getSrc(termItems[0]['thumbnail'], 'tainacan-medium', termItems[0]['document_mimetype']) :`${tainacan_blocks.base_url}/assets/images/placeholder_square.png` }
srcSet={ termItems[0] ? thumbHelper.getSrcSet(termItems[0]['thumbnail'], 'tainacan-medium', termItems[0]['document_mimetype']) :`${tainacan_blocks.base_url}/assets/images/placeholder_square.png` }
alt={ termItems[0] && termItems[0].thumbnail_alt ? termItems[0].thumbnail_alt : (termItems[0] && termItems[0].name ? termItems[0].name : __( 'Thumbnail', 'tainacan' )) } />
<img
src={ termItems[1] ? thumbHelper.getSrc(termItems[1]['thumbnail'], 'tainacan-medium', termItems[1]['document_mimetype']) :`${tainacan_blocks.base_url}/assets/images/placeholder_square.png` }
srcSet={ termItems[1] ? thumbHelper.getSrcSet(termItems[1]['thumbnail'], 'tainacan-medium', termItems[1]['document_mimetype']) :`${tainacan_blocks.base_url}/assets/images/placeholder_square.png` }
alt={ termItems[1] && termItems[1].thumbnail_alt ? termItems[1].thumbnail_alt : (termItems[1] && termItems[1].name ? termItems[1].name : __( 'Thumbnail', 'tainacan' )) } />
<img
src={ termItems[2] ? thumbHelper.getSrc(termItems[2]['thumbnail'], 'tainacan-medium', termItems[2]['document_mimetype']) :`${tainacan_blocks.base_url}/assets/images/placeholder_square.png` }
srcSet={ termItems[2] ? thumbHelper.getSrcSet(termItems[2]['thumbnail'], 'tainacan-medium', termItems[2]['document_mimetype']) :`${tainacan_blocks.base_url}/assets/images/placeholder_square.png` }
alt={ termItems[2] && termItems[2].thumbnail_alt ? termItems[2].thumbnail_alt : (termItems[2] && termItems[2].name ? termItems[2].name : __( 'Thumbnail', 'tainacan' )) } />
</div>
:
<img
src={ term.header_image ? term.header_image : `${tainacan_blocks.base_url}/assets/images/placeholder_square.png`}
alt={ term.name ? term.name : __( 'Thumbnail', 'tainacan' )}/>
}
{ !hideName ? <span>{ term.name ? term.name : '' }</span> : null }
</a>
</li>
);
}
function setContent(){
isLoading = true;
setAttributes({
isLoading: isLoading
});
if (itemsRequestSource != undefined && typeof itemsRequestSource == 'function')
itemsRequestSource.cancel('Previous terms search canceled.');
itemsRequestSource = axios.CancelToken.source();
terms = [];
let endpoint = '/taxonomy/' + taxonomyId + '/terms/?'+ qs.stringify({ hideempty: 0, include: selectedTerms.map((term) => { return term.id; }) }) + '&order=asc&fetch_only=id,name,url,header_image';
tainacan.get(endpoint, { cancelToken: itemsRequestSource.token })
.then(response => {
if (showTermThumbnail) {
for (let term of response.data) {
terms.push(prepareItem(term));
}
setAttributes({
content: <div></div>,
terms: terms,
isLoading: false,
itemsRequestSource: itemsRequestSource
});
} else {
let promises = [];
for (let term of response.data) {
promises.push(
tainacan.get('/items/?perpage=3&fetch_only=name,url,thumbnail&taxquery[0][taxonomy]=tnc_tax_' + taxonomyId + '&taxquery[0][terms][0]=' + term.id + '&taxquery[0][compare]=IN')
.then(response => { return({ term: term, termItems: response.data.items }) })
.catch((error) => console.log(error))
);
}
axios.all(promises).then((results) => {
for (let result of results) {
terms.push(prepareItem(result.term, result.termItems));
}
setAttributes({
content: <div></div>,
terms: terms,
isLoading: false,
itemsRequestSource: itemsRequestSource
});
})
}
});
}
function openCarouselModal() {
isModalOpen = true;
setAttributes( {
isModalOpen: isModalOpen
} );
}
function removeItemOfId(itemId) {
let existingItemIndex = terms.findIndex((existingItem) => existingItem.key == itemId);
if (existingItemIndex >= 0)
terms.splice(existingItemIndex, 1);
let existingSelectedItemIndex = selectedTerms.findIndex((existingSelectedItem) => existingSelectedItem.id == itemId);
if (existingSelectedItemIndex >= 0)
selectedTerms.splice(existingSelectedItemIndex, 1);
setAttributes({
selectedTerms: selectedTerms,
terms: terms,
content: <div></div>
});
}
// Executed only on the first load of page
if(content && content.length && content[0].type)
setContent();
return content == 'preview' ?
<div className={className}>
<img
width="100%"
src={ `${tainacan_blocks.base_url}/assets/images/carousel-terms-list.png` } />
</div>
: (
<div className={className}>
{ terms.length ?
<BlockControls>
{
TainacanBlocksCompatToolbar({
label: __('Add more terms', 'tainacan'),
icon: <svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -2 24 24"
height="24px"
width="24px">
<path d="M21.43,14.64,19.32,17a2.57,2.57,0,0,1-2,1H12.05a6,6,0,0,0-6-6H6V10.64A2.59,2.59,0,0,1,8.59,8H17.3a2.57,2.57,0,0,1,2,1l2.11,2.38A2.59,2.59,0,0,1,21.43,14.64ZM4,4A2,2,0,0,0,2,6v7.63a5.74,5.74,0,0,1,2-1.2V6H16V4ZM7,15.05v6.06l3.06-3.06ZM5,21.11V15.05L1.94,18.11Z"/>
</svg>,
onClick: openCarouselModal
})
}
</BlockControls>
: null }
<div>
<InspectorControls>
<PanelBody
title={__('Carousel', 'tainacan')}
initialOpen={ true }
>
<BaseControl
id="term-carousel-view-modes"
label={ __('Term layout', 'tainacan')}>
<div className="term-carousel-view-modes">
<button
onClick={ () => {
showTermThumbnail = false;
setAttributes({ showTermThumbnail: showTermThumbnail });
setContent();
}
}
className={'term-carousel-view-mode-grid' + (showTermThumbnail ? '' : ' is-active')}>
<div>
<div />
<div />
<div />
</div>
<label>{ __('Items\'s grid', 'tainacan') }</label>
</button>
<button
onClick={ () => {
showTermThumbnail = true;
setAttributes({ showTermThumbnail: showTermThumbnail });
setContent();
}
}
className={'term-carousel-view-mode-thumbnail' + (showTermThumbnail ? ' is-active' : '')}>
<div />
<label>{ __('Thumbnail', 'tainacan') }</label>
</button>
</div>
</BaseControl>
<RangeControl
label={ __('Maximum terms per slide on a wide screen', 'tainacan') }
help={ (showTermThumbnail && maxTermsPerScreen <= 3) ? __('Warning: with such a small number of terms per slide, the image size is greater and might be pixelated.', 'tainacan') : null }
value={ maxTermsPerScreen ? maxTermsPerScreen : 6 }
onChange={ ( aMaxTermsPerScreen ) => {
maxTermsPerScreen = aMaxTermsPerScreen;
setAttributes( { maxTermsPerScreen: aMaxTermsPerScreen } );
setContent();
}}
min={ 1 }
max={ 9 }
/>
<ToggleControl
label={__('Hide name', 'tainacan')}
help={ !hideName ? __('Toggle to hide term\'s name', 'tainacan') : __('Do not hide term\'s name', 'tainacan')}
checked={ hideName }
onChange={ ( isChecked ) => {
hideName = isChecked;
setAttributes({ hideName: hideName });
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 term', 'tainacan') : __('Do not automatically slide to next term', 'tainacan')}
checked={ autoPlay }
onChange={ ( isChecked ) => {
autoPlay = isChecked;
setAttributes({ autoPlay: autoPlay });
}
}
/>
{
autoPlay ?
<RangeControl
label={__('Seconds before translating to next', 'tainacan')}
value={ autoPlaySpeed ? autoPlaySpeed : 3 }
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 });
}}/>
<ToggleControl
label={__('Large arrows', 'tainacan')}
help={ !largeArrows ? __('Toggle to display arrows bigger than the default size.', 'tainacan') : __('Do not show arrows bigger than the default size.', 'tainacan')}
checked={ largeArrows }
onChange={ ( isChecked ) => {
largeArrows = isChecked;
setAttributes({ largeArrows: largeArrows });
}
}
/>
</PanelBody>
</InspectorControls>
</div>
{ isSelected ?
(
<div>
{ isModalOpen ?
<TermsModal
replaceTermId={ false } // The Terms modal adds `term-id-` string to terms ids. Here we dont' need it
existingTaxonomyId={ taxonomyId }
selectedTermsObject={ selectedTerms }
onSelectTaxonomy={ (selectedTaxonomyId) => {
taxonomyId = selectedTaxonomyId;
setAttributes({ taxonomyId: taxonomyId });
}}
onApplySelection={ (aSelectionOfTerms) =>{
selectedTerms = aSelectionOfTerms;
setAttributes({
selectedTerms: selectedTerms,
isModalOpen: false
});
setContent();
}}
onCancelSelection={ () => setAttributes({ isModalOpen: false }) }/>
: null
}
</div>
) : null
}
{ !terms.length && !isLoading ? (
<Placeholder
className="tainacan-block-placeholder"
icon={(
<img
width={148}
src={ `${tainacan_blocks.base_url}/assets/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="M21.43,14.64,19.32,17a2.57,2.57,0,0,1-2,1H12.05a6,6,0,0,0-6-6H6V10.64A2.59,2.59,0,0,1,8.59,8H17.3a2.57,2.57,0,0,1,2,1l2.11,2.38A2.59,2.59,0,0,1,21.43,14.64ZM4,4A2,2,0,0,0,2,6v7.63a5.74,5.74,0,0,1,2-1.2V6H16V4ZM7,15.05v6.06l3.06-3.06ZM5,21.11V15.05L1.94,18.11Z"/>
</svg>
{__('List terms on a Carousel, showing their thumbnails or a preview of items.', 'tainacan')}
</p>
<Button
isPrimary
type="button"
onClick={ () => openCarouselModal() }>
{__('Select Terms', 'tainacan')}
</Button>
</Placeholder>
) : null
}
{ isLoading ?
<div class="spinner-container">
<Spinner />
</div> :
<div>
{ isSelected && terms.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
}
{ terms.length ? (
<div
className={'terms-list-edit-container ' + (arrowsPosition ? 'has-arrows-' + arrowsPosition : '') + (largeArrows ? ' has-large-arrows' : '') }>
<button
class="swiper-button-prev"
slot="button-prev"
style={{ cursor: 'not-allowed' }}>
<svg
width={ largeArrows ? 60 : 42 }
height={ largeArrows ? 60 : 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={'terms-list-edit'}>
{ terms }
</ul>
<button
class="swiper-button-next"
slot="button-next"
style={{ cursor: 'not-allowed' }}>
<svg
width={ largeArrows ? 60 : 42 }
height={ largeArrows ? 60 : 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,
selectedTerms,
arrowsPosition,
largeArrows,
maxTermsPerScreen,
maxTermsNumber,
autoPlay,
autoPlaySpeed,
loopSlides,
hideName,
showTermThumbnail,
taxonomyId
} = attributes;
return <div
className={ className }
selected-terms={ JSON.stringify(selectedTerms.map((term) => { return term.id; })) }
arrows-position={ arrowsPosition }
auto-play={ '' + autoPlay }
auto-play-speed={ autoPlaySpeed }
loop-slides={ '' + loopSlides }
hide-name={ '' + hideName }
large-arrows={ '' + largeArrows }
max-terms-number={ maxTermsNumber }
max-terms-per-screen={ maxTermsPerScreen }
taxonomy-id={ taxonomyId }
tainacan-api-root={ tainacan_blocks.root }
tainacan-base-url={ tainacan_blocks.base_url }
show-term-thumbnail={ '' + showTermThumbnail }
id={ 'wp-block-tainacan-carousel-terms-list_' + blockId }>
{ content }
</div>
},
deprecated: DeprecatedBlocks
});
tainacanRegisterBlockType({
metadata,
icon,
edit,
save,
deprecated
});

View File

@ -0,0 +1,35 @@
export default function({ attributes, className }) {
const {
content,
blockId,
selectedTerms,
arrowsPosition,
largeArrows,
maxTermsPerScreen,
maxTermsNumber,
autoPlay,
autoPlaySpeed,
loopSlides,
hideName,
showTermThumbnail,
taxonomyId
} = attributes;
return <div
className={ className }
selected-terms={ JSON.stringify(selectedTerms.map((term) => { return term.id; })) }
arrows-position={ arrowsPosition }
auto-play={ '' + autoPlay }
auto-play-speed={ autoPlaySpeed }
loop-slides={ '' + loopSlides }
hide-name={ '' + hideName }
large-arrows={ '' + largeArrows }
max-terms-number={ maxTermsNumber }
max-terms-per-screen={ maxTermsPerScreen }
taxonomy-id={ taxonomyId }
tainacan-api-root={ tainacan_blocks.root }
tainacan-base-url={ tainacan_blocks.base_url }
show-term-thumbnail={ '' + showTermThumbnail }
id={ 'wp-block-tainacan-carousel-terms-list_' + blockId }>
{ content }
</div>
};

View File

@ -382,7 +382,9 @@
.term-items-grid {
@include display-grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 50% 50%;
grid-template-rows: 1fr 1fr;
grid-gap: 5px;
gap: 5px;
img:first-of-type {
flex-basis: 100%;
@ -391,7 +393,6 @@
img {
flex-basis: 50%;
padding: 2px;
margin-bottom: 0px;
}
}

View File

@ -0,0 +1,149 @@
{
"name": "tainacan/dynamic-items-list",
"title": "Tainacan Collection\"s Items List",
"category": "tainacan-blocks",
"keywords": [ "items", "search", "collection" ],
"description": "Dynamically list items from a Tainacan items search",
"example": {
"attributes": {
"content": "preview"
}
},
"attributes": {
"content": {
"type": "Array",
"source": "children",
"selector": "div"
},
"collectionId": {
"type": "String",
"default": ""
},
"items": {
"type": "Array",
"default": []
},
"showImage": {
"type": "Boolean",
"default": true
},
"showName": {
"type": "Boolean",
"default": true
},
"layout": {
"type": "String",
"default": "grid"
},
"isModalOpen": {
"type": "Boolean",
"default": false
},
"gridMargin": {
"type": "Number",
"default": 0
},
"searchURL": {
"type": "String",
"default": ""
},
"itemsRequestSource": {
"type": "String",
"default": ""
},
"maxItemsNumber": {
"type": "Number",
"value": 12
},
"isLoading": {
"type": "Boolean",
"value": false
},
"isLoadingCollection": {
"type": "Boolean",
"value": false
},
"showSearchBar": {
"type": "Boolean",
"value": false
},
"showCollectionHeader": {
"type": "Boolean",
"value": false
},
"showCollectionLabel": {
"type": "Boolean",
"value": false
},
"collection": {
"type": "Object",
"value": {}
},
"searchString": {
"type": "String",
"default": ""
},
"order": {
"type": "String",
"default": "asc"
},
"blockId": {
"type": "String",
"default": ""
},
"collectionBackgroundColor": {
"type": "String",
"default": "#454647"
},
"collectionTextColor": {
"type": "String",
"default": "#ffffff"
},
"mosaicHeight": {
"type": "Number",
"value": 280
},
"mosaicGridColumns": {
"type": "Number",
"value": 3
},
"mosaicGridRows": {
"type": "Number",
"value": 3
},
"sampleBackgroundImage": {
"type": "String",
"default": ""
},
"mosaicItemFocalPoint": {
"type": "Object",
"default": {
"x": 0.5,
"y": 0.5
}
},
"mosaicDensity": {
"type": "Number",
"default": 5
},
"maxColumnsCount": {
"type": "Number",
"default": 4
},
"cropImagesToSquare": {
"type": "Boolean",
"value": true
}
},
"supports": {
"align": ["full", "wide"],
"html": false,
"typography": {
"fontSize": true
}
},
"editorScript": "dynamic-items-list",
"script": "dynamic-items-list-theme",
"editorStyle": "dynamic-items-list",
"style": "dynamic-items-list"
}

View File

@ -1,4 +1,193 @@
export default [
/* Deprecated on Tainacan 0.18.4, due to the new block.json strategy */
{
attributes: {
content: {
type: 'array',
source: 'children',
selector: 'div'
},
collectionId: {
type: String,
default: undefined
},
items: {
type: Array,
default: []
},
showImage: {
type: Boolean,
default: true
},
showName: {
type: Boolean,
default: true
},
layout: {
type: String,
default: 'grid'
},
isModalOpen: {
type: Boolean,
default: false
},
gridMargin: {
type: Number,
default: 0
},
searchURL: {
type: String,
default: undefined
},
itemsRequestSource: {
type: String,
default: undefined
},
maxItemsNumber: {
type: Number,
value: undefined
},
isLoading: {
type: Boolean,
value: false
},
isLoadingCollection: {
type: Boolean,
value: false
},
showSearchBar: {
type: Boolean,
value: false
},
showCollectionHeader: {
type: Boolean,
value: false
},
showCollectionLabel: {
type: Boolean,
value: false
},
collection: {
type: Object,
value: undefined
},
searchString: {
type: String,
default: undefined
},
order: {
type: String,
default: undefined
},
blockId: {
type: String,
default: undefined
},
collectionBackgroundColor: {
type: String,
default: "#454647"
},
collectionTextColor: {
type: String,
default: "#ffffff"
},
mosaicHeight: {
type: Number,
value: 280
},
mosaicGridColumns: {
type: Number,
value: 3
},
mosaicGridRows: {
type: Number,
value: 3
},
sampleBackgroundImage: {
type: String,
default: ''
},
mosaicItemFocalPoint: {
type: Object,
default: {
x: 0.5,
y: 0.5
}
},
mosaicDensity: {
type: Number,
default: 5
},
maxColumnsCount: {
type: Number,
default: 4
},
cropImagesToSquare: {
type: Boolean,
value: true
}
},
supports: {
align: ['full', 'wide'],
html: false,
fontSize: true
},
save({ attributes, className }){
const {
content,
blockId,
collectionId,
showImage,
showName,
layout,
gridMargin,
searchURL,
maxItemsNumber,
order,
showSearchBar,
showCollectionHeader,
showCollectionLabel,
collectionBackgroundColor,
collectionTextColor,
mosaicHeight,
mosaicGridRows,
mosaicGridColumns,
mosaicItemFocalPoint,
mosaicDensity,
maxColumnsCount,
cropImagesToSquare
} = attributes;
return <div
search-url={ searchURL }
className={ className }
collection-id={ collectionId }
show-image={ '' + showImage }
show-name={ '' + showName }
show-search-bar={ '' + showSearchBar }
show-collection-header={ '' + showCollectionHeader }
show-collection-label={ '' + showCollectionLabel }
crop-images-to-square={ '' + cropImagesToSquare }
layout={ layout }
mosaic-height={ mosaicHeight }
mosaic-density={ mosaicDensity }
mosaic-grid-rows={ mosaicGridRows }
mosaic-grid-columns={ mosaicGridColumns }
mosaic-item-focal-point-x={ (mosaicItemFocalPoint && mosaicItemFocalPoint.x ? mosaicItemFocalPoint.x : 0.5) }
mosaic-item-focal-point-y={ (mosaicItemFocalPoint && mosaicItemFocalPoint.y ? mosaicItemFocalPoint.y : 0.5) }
max-columns-count={ maxColumnsCount }
collection-background-color={ collectionBackgroundColor }
collection-text-color={ collectionTextColor }
grid-margin={ gridMargin }
max-items-number={ maxItemsNumber }
order={ order }
tainacan-api-root={ tainacan_blocks.root }
tainacan-base-url={ tainacan_blocks.base_url }
id={ 'wp-block-tainacan-dynamic-items-list_' + blockId }>
{ content }
</div>
}
},
/* Deprecated on Tainacan 0.18, due to the introduction of maxColumnsCount and fix of osaicItemFocalPointm */
{
attributes: {

View File

@ -40,7 +40,7 @@ export default class DynamicItemsModal extends React.Component {
collectionId: this.props.existingCollectionId
});
if (this.props.existingCollectionId != null && this.props.existingCollectionId != undefined) {
if (this.props.existingCollectionId) {
this.fetchCollection(this.props.existingCollectionId);
this.setState({ searchURL: this.props.existingSearchURL ? this.props.existingSearchURL : tainacan_blocks.admin_url + 'admin.php?page=tainacan_admin#/collections/'+ this.props.existingCollectionId + '/items/?readmode=true&iframemode=true&status=publish' });
} else {
@ -165,7 +165,7 @@ export default class DynamicItemsModal extends React.Component {
}
render() {
return this.state.collectionId != null && this.state.collectionId != undefined ? (
return this.state.collectionId ? (
// Items modal
<Modal
className="wp-block-tainacan-modal dynamic-modal"

View File

@ -0,0 +1,876 @@
const { __ } = wp.i18n;
const { ResizableBox, FocalPointPicker, SelectControl, RangeControl, Spinner, Button, ToggleControl, Placeholder, ColorPicker, ColorPalette, BaseControl, PanelBody } = wp.components;
const { InspectorControls, BlockControls } = ( tainacan_blocks.wp_version < '5.2' ? wp.editor : wp.blockEditor );
import DynamicItemsModal from './dynamic-items-modal.js';
import tainacan from '../../js/axios.js';
import axios from 'axios';
import qs from 'qs';
import { ThumbnailHelperFunctions } from '../../../admin/js/utilities.js';
import TainacanBlocksCompatToolbar from '../../js/tainacan-blocks-compat-toolbar.js';
export default function({ attributes, setAttributes, className, isSelected, clientId }){
let {
items,
content,
collection,
collectionId,
showImage,
showName,
layout,
isModalOpen,
gridMargin,
searchURL,
itemsRequestSource,
maxItemsNumber,
order,
searchString,
isLoading,
showSearchBar,
showCollectionHeader,
showCollectionLabel,
isLoadingCollection,
collectionBackgroundColor,
collectionTextColor,
mosaicHeight,
mosaicGridColumns,
mosaicGridRows,
mosaicItemFocalPoint,
sampleBackgroundImage,
mosaicDensity,
maxColumnsCount,
cropImagesToSquare
} = attributes;
// Obtains block's client id to render it on save function
setAttributes({ blockId: clientId });
// Sets some defaults that were not working
if (maxColumnsCount === undefined) {
maxColumnsCount = 5;
setAttributes({ maxColumnsCount: maxColumnsCount });
}
if (cropImagesToSquare === undefined) {
cropImagesToSquare = true;
setAttributes({ cropImagesToSquare: cropImagesToSquare });
}
const thumbHelper = ThumbnailHelperFunctions();
function prepareItem(item) {
return (
<li
key={ item.id }
className="item-list-item"
style={ {
backgroundImage: layout == 'mosaic' ? `url(${ thumbHelper.getSrc(item['thumbnail'], 'medium_large', item['document_mimetype']) })` : 'none',
backgroundPosition: layout == 'mosaic' ? `${ (mosaicItemFocalPoint && mosaicItemFocalPoint.x ? mosaicItemFocalPoint.x : 0.5) * 100 }% ${ (mosaicItemFocalPoint && mosaicItemFocalPoint.y ? mosaicItemFocalPoint.y : 0.5) * 100 }%` : 'none'
}}
>
<a
id={ isNaN(item.id) ? item.id : 'item-id-' + item.id }
href={ item.url }
onClick={ (event) => event.preventDefault() }
target="_blank"
style={ {
} }
className={ (!showName ? 'item-without-title' : '') + ' ' + (!showImage ? 'item-without-image' : '') }>
<img
src={ thumbHelper.getSrc(item['thumbnail'], ( (layout == 'list' || cropImagesToSquare) ? 'tainacan-medium' : 'tainacan-medium-full'), item['document_mimetype']) }
srcSet={ thumbHelper.getSrcSet(item['thumbnail'], ( (layout == 'list' || cropImagesToSquare) ? 'tainacan-medium' : 'tainacan-medium-full'), item['document_mimetype']) }
alt={ item.thumbnail_alt ? item.thumbnail_alt : (item && item.title ? item.title : __( 'Thumbnail', 'tainacan' )) }/>
<span>{ item.title ? item.title : '' }</span>
</a>
</li>
);
}
function prepareMosaicItem(mosaicGroup, mosaicGroupsLength) {
return (
<div
style={
{
width: 'calc((100% / ' + mosaicGroupsLength + ') - ' + gridMargin + 'px)',
height: 'calc(((' + (mosaicGridRows - 1) + ' * ' + gridMargin + 'px) + ' + mosaicHeight + 'px))',
gridTemplateColumns: 'repeat(' + mosaicGridColumns + ', calc((100% / ' + mosaicGridColumns + ') - (' + ((mosaicGridColumns - 1)*Number(gridMargin)) + 'px/' + mosaicGridColumns + ')))',
margin: gridMargin + 'px',
gridGap: gridMargin + 'px',
}
}
className={ 'mosaic-container mosaic-container--' + mosaicGroup.length + '-' + mosaicGridRows + 'x' + mosaicGridColumns }>
{ buildMosaic(mosaicGroup) }
</div>
)
}
function setContent(){
if (searchURL) {
items = [];
isLoading = true;
if (itemsRequestSource != undefined && typeof itemsRequestSource == 'function')
itemsRequestSource.cancel('Previous items search canceled.');
itemsRequestSource = axios.CancelToken.source();
setAttributes({
isLoading: isLoading
});
let endpoint = '/collection' + searchURL.split('#')[1].split('/collections')[1];
let query = endpoint.split('?')[1];
let queryObject = qs.parse(query);
// Set up max items to be shown
if (maxItemsNumber != undefined && maxItemsNumber > 0)
queryObject.perpage = maxItemsNumber;
else if (queryObject.perpage != undefined && queryObject.perpage > 0)
setAttributes({ maxItemsNumber: queryObject.perpage });
else {
queryObject.perpage = 12;
setAttributes({ maxItemsNumber: 12 });
}
// Set up sorting order
if (!order)
queryObject.order = order;
else if (!queryObject.order)
setAttributes({ order: queryObject.order });
else {
queryObject.order = 'asc';
setAttributes({ order: 'asc' });
}
// Set up sorting order
if (searchString != undefined)
queryObject.search = searchString;
else if (queryObject.search != undefined)
setAttributes({ searchString: queryObject.search });
else {
delete queryObject.search;
setAttributes({ searchString: undefined });
}
// Remove unecessary queries
delete queryObject.readmode;
delete queryObject.iframemode;
delete queryObject.admin_view_mode;
delete queryObject.fetch_only_meta;
endpoint = endpoint.split('?')[0] + '?' + qs.stringify(queryObject) + '&fetch_only=title,url,thumbnail';
tainacan.get(endpoint, { cancelToken: itemsRequestSource.token })
.then(response => {
if (layout !== 'mosaic') {
for (let item of response.data.items)
items.push(prepareItem(item));
setAttributes({
content: <div></div>,
items: items,
isLoading: false,
itemsRequestSource: itemsRequestSource
});
} else {
// Initializes some variables
mosaicDensity = mosaicDensity ? mosaicDensity : 5;
mosaicGridRows = mosaicGridRows ? mosaicGridRows : 3;
mosaicGridColumns = mosaicGridColumns ? mosaicGridColumns : 3;
mosaicHeight = mosaicHeight ? mosaicHeight : 280;
mosaicItemFocalPoint = mosaicItemFocalPoint ? mosaicItemFocalPoint : { x: 0.5, y: 0.5 };
sampleBackgroundImage = response.data.items && response.data.items[0] && response.data.items[0] ? getItemThumbnail(response.data.items[0], 'tainacan-medium') : '';
const mosaicGroups = mosaicPartition(response.data.items);
for (let mosaicGroup of mosaicGroups)
items.push(prepareMosaicItem(mosaicGroup, mosaicGroups.length));
setAttributes({
content: <div></div>,
items: items,
isLoading: false,
itemsRequestSource: itemsRequestSource,
mosaicDensity: mosaicDensity,
mosaicHeight: mosaicHeight,
mosaicGridRows: mosaicGridRows,
mosaicGridColumns: mosaicGridColumns,
mosaicItemFocalPoint: mosaicItemFocalPoint,
sampleBackgroundImage: sampleBackgroundImage
});
}
});
}
}
function fetchCollectionForHeader() {
if (showCollectionHeader) {
isLoadingCollection = true;
setAttributes({
isLoadingCollection: isLoadingCollection
});
tainacan.get('/collections/' + collectionId + '?fetch_only=name,thumbnail,header_image')
.then(response => {
collection = response.data;
isLoadingCollection = false;
if (collection.tainacan_theme_collection_background_color)
collectionBackgroundColor = collection.tainacan_theme_collection_background_color;
else
collectionBackgroundColor = '#454647';
if (collection.tainacan_theme_collection_color)
collectionTextColor = collection.tainacan_theme_collection_color;
else
collectionTextColor = '#ffffff';
setAttributes({
content: <div></div>,
collection: collection,
isLoadingCollection: isLoadingCollection,
collectionBackgroundColor: collectionBackgroundColor,
collectionTextColor: collectionTextColor
});
});
}
}
function getItemThumbnail(item, size) {
return (
item.thumbnail && item.thumbnail[size][0] && item.thumbnail[size][0]
?
item.thumbnail[size][0]
:
(item.thumbnail && item.thumbnail['thumbnail'][0] && item.thumbnail['thumbnail'][0]
?
item.thumbnail['thumbnail'][0]
:
`${tainacan_blocks.base_url}/assets/images/placeholder_square.png`)
)
}
function openDynamicItemsModal() {
isModalOpen = true;
setAttributes( {
isModalOpen: isModalOpen
} );
}
function updateLayout(newLayout) {
layout = newLayout;
if ((layout == 'grid' || layout == 'mosaic') && showImage == false)
showImage = true;
if (layout == 'list' && showName == false)
showName = true;
setAttributes({
layout: layout,
showImage: showImage,
showName: showName
});
setContent();
}
function applySearchString(event) {
let value = event.target.value;
if (searchString != value) {
searchString = value;
setAttributes({ searchString: searchString });
setContent();
}
}
function updateMosaicItemFocalPoint(focalPoint) {
if (Math.abs(focalPoint.x - (mosaicItemFocalPoint && mosaicItemFocalPoint.x ? mosaicItemFocalPoint.x : 0.5)) > 0.025 || Math.abs(focalPoint.y - (mosaicItemFocalPoint && mosaicItemFocalPoint.y ? mosaicItemFocalPoint.y : 0.5)) > 0.025) {
mosaicItemFocalPoint = focalPoint;
setAttributes({ mosaicItemFocalPoint: focalPoint });
setContent();
}
}
function mosaicPartition(items) {
const partition = _.groupBy(items, (item, i) => {
if (i % 2 == 0)
return Math.floor(i/mosaicDensity)
else
return Math.floor(i/(mosaicDensity + 1))
});
return _.values(partition);
}
function buildMosaic(mosaicGroup) {
let mosaic = []
for (let item of mosaicGroup)
mosaic.push(prepareItem(item))
return mosaic;
}
// Executed only on the first load of page
if(content && content.length && content[0].type)
setContent();
const layoutControls = [
{
icon: 'grid-view',
title: __( 'Grid View', 'tainacan' ),
onClick: () => updateLayout('grid'),
isActive: layout === 'grid',
},
{
icon: 'list-view',
title: __( 'List View', 'tainacan' ),
onClick: () => updateLayout('list'),
isActive: layout === 'list',
},
{
icon: 'layout',
title: __( 'Mosaic View', 'tainacan' ),
onClick: () => updateLayout('mosaic'),
isActive: layout === 'mosaic',
}
];
return content == 'preview' ?
<div className={className}>
<img
width="100%"
src={ `${tainacan_blocks.base_url}/assets/images/dynamic-items-list.png` } />
</div>
: (
<div className={className}>
<div>
<BlockControls>
{ TainacanBlocksCompatToolbar({ controls: layoutControls }) }
{ items.length ?
TainacanBlocksCompatToolbar({
label: __('Configure search', 'tainacan'),
icon: <svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -2 24 24"
height="24px"
width="24px">
<path d="M14,2V4H7v7.24A5.33,5.33,0,0,0,5.5,11a4.07,4.07,0,0,0-.5,0V4A2,2,0,0,1,7,2Zm7,10v8a2,2,0,0,1-2,2H12l1-1-2.41-2.41A5.56,5.56,0,0,0,11,16.53a5.48,5.48,0,0,0-2-4.24V8a2,2,0,0,1,2-2h4Zm-2.52,0L14,7.5V12ZM11,21l-1,1L8.86,20.89,8,20H8l-.57-.57A3.42,3.42,0,0,1,5.5,20a3.5,3.5,0,0,1-.5-7,2.74,2.74,0,0,1,.5,0,3.41,3.41,0,0,1,1.5.34,3.5,3.5,0,0,1,2,3.16,3.42,3.42,0,0,1-.58,1.92L9,19H9l.85.85Zm-4-4.5A1.5,1.5,0,0,0,5.5,15a1.39,1.39,0,0,0-.5.09A1.5,1.5,0,0,0,5.5,18a1.48,1.48,0,0,0,1.42-1A1.5,1.5,0,0,0,7,16.53Z"/>
</svg>,
onClick: openDynamicItemsModal
})
: null }
</BlockControls>
</div>
<div>
<InspectorControls>
<PanelBody
title={__('Collection header', 'tainacan')}
initialOpen={ false }
>
<ToggleControl
label={__('Display header', 'tainacan')}
help={ !showCollectionHeader ? __('Toggle to show collection header', 'tainacan') : __('Do not show collection header', 'tainacan')}
checked={ showCollectionHeader }
onChange={ ( isChecked ) => {
showCollectionHeader = isChecked;
if (isChecked) fetchCollectionForHeader();
setAttributes({ showCollectionHeader: showCollectionHeader });
}
}
/>
{ showCollectionHeader ?
<div style={{ margin: '6px' }}>
<ToggleControl
label={__('Display "Collection" label', 'tainacan')}
help={ !showCollectionLabel ? __('Toggle to show "Collection" label above header', 'tainacan') : __('Do not show "Collection" label', 'tainacan')}
checked={ showCollectionLabel }
onChange={ ( isChecked ) => {
showCollectionLabel = isChecked;
setAttributes({ showCollectionLabel: showCollectionLabel });
}
}
/>
<BaseControl
id="colorpicker"
label={ __('Background color', 'tainacan')}>
<ColorPicker
color={ collectionBackgroundColor }
onChangeComplete={ ( value ) => {
collectionBackgroundColor = value.hex;
setAttributes({ collectionBackgroundColor: collectionBackgroundColor })
}}
disableAlpha
/>
</BaseControl>
<BaseControl
id="colorpallete"
label={ __('Collection name color', 'tainacan')}>
<ColorPalette
colors={ [{ name: __('Black', 'tainacan'), color: '#000000'}, { name: __('White', 'tainacan'), color: '#ffffff'} ] }
value={ collectionTextColor }
onChange={ ( color ) => {
collectionTextColor = color;
setAttributes({ collectionTextColor: collectionTextColor })
}}
/>
</BaseControl>
</div>
: null
}
</PanelBody>
<PanelBody
title={__('Search bar', 'tainacan')}
initialOpen={ true }
>
<ToggleControl
label={__('Display bar', 'tainacan')}
help={ showSearchBar ? __('Toggle to show search bar on block', 'tainacan') : __('Do not show search bar', 'tainacan')}
checked={ showSearchBar }
onChange={ ( isChecked ) => {
showSearchBar = isChecked;
setAttributes({ showSearchBar: showSearchBar });
}
}
/>
</PanelBody>
<PanelBody
title={__('Items', 'tainacan')}
initialOpen={ true }
>
<div>
<RangeControl
label={__('Maximum number of items', 'tainacan')}
value={ maxItemsNumber ? maxItemsNumber : 12 }
onChange={ ( aMaxItemsNumber ) => {
maxItemsNumber = aMaxItemsNumber;
setAttributes( { maxItemsNumber: aMaxItemsNumber } )
setContent();
}}
min={ 1 }
max={ 96 }
/>
</div>
<hr></hr>
<div>
{ layout == 'list' ?
<div style={{ marginTop: '16px'}}>
<RangeControl
label={ __('Maximum number of columns on a wide screen', 'tainacan') }
value={ maxColumnsCount ? maxColumnsCount : 5 }
onChange={ ( aMaxColumnsCount ) => {
maxColumnsCount = aMaxColumnsCount;
setAttributes( { maxColumnsCount: aMaxColumnsCount } );
setContent();
}}
min={ 1 }
max={ 7 }
/>
<ToggleControl
label={__('Image', 'tainacan')}
help={ showImage ? __("Toggle to show item's image", 'tainacan') : __("Do not show item's image", 'tainacan')}
checked={ showImage }
onChange={ ( isChecked ) => {
showImage = isChecked;
setAttributes({ showImage: showImage });
setContent();
}
}
/>
</div>
: null }
{ layout == 'grid' || layout == 'mosaic' ?
<div>
<ToggleControl
label={__("Item's title", 'tainacan')}
help={ showName ? __("Toggle to show item's title", 'tainacan') : __("Do not show item's title", 'tainacan')}
checked={ showName }
onChange={ ( isChecked ) => {
showName = isChecked;
setAttributes({ showName: showName });
setContent();
}
}
/>
<div style={{ marginTop: '16px'}}>
<RangeControl
label={__('Margin between items in pixels', 'tainacan')}
value={ gridMargin ? gridMargin : 0 }
onChange={ ( margin ) => {
gridMargin = margin;
setAttributes( { gridMargin: margin } );
setContent();
}}
min={ 0 }
max={ 48 }
/>
</div>
</div>
: null }
{ layout == 'grid' ?
<div style={{ marginTop: '16px'}}>
<RangeControl
label={ __('Maximum number of columns on a wide screen', 'tainacan') }
value={ maxColumnsCount ? maxColumnsCount : 5 }
onChange={ ( aMaxColumnsCount ) => {
maxColumnsCount = aMaxColumnsCount;
setAttributes( { maxColumnsCount: aMaxColumnsCount } );
setContent();
}}
min={ 1 }
max={ 7 }
/>
<ToggleControl
label={__('Crop Images', 'tainacan')}
help={ cropImagesToSquare ? __('Do not use square cropeed version of the item thumbnail.', 'tainacan') : __('Toggle to use square cropped version of the item thumbnail.', 'tainacan') }
checked={ cropImagesToSquare }
onChange={ ( isChecked ) => {
cropImagesToSquare = isChecked;
setAttributes({ cropImagesToSquare: cropImagesToSquare });
setContent();
}
}
/>
</div>
: null }
</div>
</PanelBody>
{ layout == 'mosaic' ?
<PanelBody
title={__('Mosaic', 'tainacan')}
initialOpen={ true }
>
<div>
<RangeControl
label={__('Container height (px)', 'tainacan')}
value={ mosaicHeight ? mosaicHeight : 280 }
onChange={ ( height ) => {
mosaicHeight = height;
setAttributes( { mosaicHeight: height } );
setContent();
}}
min={ 100 }
max={ 2000 }
/>
</div>
<div>
<RangeControl
label={__('Group Grid Density', 'tainacan')}
value={ mosaicDensity ? mosaicDensity : 5 }
onChange={ ( value ) => {
mosaicDensity = value;
setAttributes( { mosaicDensity: mosaicDensity } );
setContent();
}}
min={ 1 }
max={ 5 }
/>
</div>
<div>
<SelectControl
label={__('Group Grid Dimensions', 'tainacan')}
value={ mosaicGridRows + 'x' + mosaicGridColumns }
options={ [
{ label: '2 x 3', value: '2x3' },
{ label: '3 x 2', value: '3x2' },
{ label: '3 x 3', value: '3x3' },
{ label: '3 x 4', value: '3x4' },
{ label: '4 x 3', value: '4x3' },
{ label: '4 x 5', value: '4x5' },
{ label: '5 x 4', value: '5x4' },
] }
onChange={ ( aGrid ) => {
mosaicGridRows = aGrid.split('x')[0];
mosaicGridColumns = aGrid.split('x')[1];
setAttributes({
mosaicGridRows: mosaicGridRows,
mosaicGridColumns: mosaicGridColumns
});
setContent();
}}/>
</div>
<div>
<FocalPointPicker
label={ __('Item focal point for background image', 'tainacan') }
url={ sampleBackgroundImage }
dimensions={ {
width: 400,
height: 400
} }
value={ mosaicItemFocalPoint }
onChange={ ( focalPoint ) =>_.debounce( updateMosaicItemFocalPoint(focalPoint), 700) }
/>
</div>
</PanelBody>
: null}
</InspectorControls>
</div>
{ isSelected ?
(
<div>
{ isModalOpen ?
<DynamicItemsModal
existingCollectionId={ collectionId }
existingSearchURL={ searchURL }
onSelectCollection={ (selectedCollectionId) => {
collectionId = selectedCollectionId;
setAttributes({ collectionId: collectionId });
fetchCollectionForHeader();
}}
onApplySearchURL={ (aSearchURL) =>{
searchURL = aSearchURL
setAttributes({
searchURL: searchURL,
isModalOpen: false
});
setContent();
}}
onCancelSelection={ () => setAttributes({ isModalOpen: false }) }/>
: null
}
</div>
) : null
}
{
showCollectionHeader ?
<div> {
isLoadingCollection ?
<div class="spinner-container">
<Spinner />
</div>
:
<a
href={ collection.url ? collection.url : '' }
target="_blank"
class="dynamic-items-collection-header">
<div
style={{
backgroundColor: collectionBackgroundColor ? collectionBackgroundColor : '',
paddingRight: collection && collection.thumbnail && (collection.thumbnail['tainacan-medium'] || collection.thumbnail['medium']) ? '' : '20px',
paddingTop: (!collection || !collection.thumbnail || (!collection.thumbnail['tainacan-medium'] && !collection.thumbnail['medium'])) ? '1rem' : '',
width: collection && collection.header_image ? '' : '100%'
}}
className={
'collection-name ' +
((!collection || !collection.thumbnail || (!collection.thumbnail['tainacan-medium'] && !collection.thumbnail['medium'])) && (!collection || !collection.header_image) ? 'only-collection-name' : '')
}>
<h3 style={{ color: collectionTextColor ? collectionTextColor : '' }}>
{ showCollectionLabel ? <span class="label">{ __('Collection', 'tainacan') }<br/></span> : null }
{ collection && collection.name ? collection.name : '' }
</h3>
</div>
{
collection && collection.thumbnail && (collection.thumbnail['tainacan-medium'] || collection.thumbnail['medium']) ?
<div
class="collection-thumbnail"
style={{
backgroundImage: 'url(' + (collection.thumbnail['tainacan-medium'] != undefined ? (collection.thumbnail['tainacan-medium'][0]) : (collection.thumbnail['medium'][0])) + ')',
}}/>
: null
}
<div
class="collection-header-image"
style={{
backgroundImage: collection.header_image ? 'url(' + collection.header_image + ')' : '',
minHeight: collection && collection.header_image ? '' : '80px',
display: !(collection && collection.thumbnail && (collection.thumbnail['tainacan-medium'] || collection.thumbnail['medium'])) ? collection && collection.header_image ? '' : 'none' : ''
}}/>
</a>
}
</div>
: null
}
{
showSearchBar ?
<div class="dynamic-items-search-bar">
<Button
onClick={ () => { order = 'asc'; setAttributes({ order: order }); setContent(); }}
className={order == 'asc' ? 'sorting-button-selected' : ''}
label={__('Sort ascending', 'tainacan')}>
<span class="icon">
<i>
<svg width="24" height="24" viewBox="-2 -4 20 20">
<path d="M6.7,10.8l-3.3,3.3L0,10.8h2.5V0h1.7v10.8H6.7z M11.7,0.8H8.3v1.7h3.3V0.8z M14.2,5.8H8.3v1.7h5.8V5.8z M16.7,10.8H8.3v1.7 h8.3V10.8z"/>
</svg>
</i>
</span>
</Button>
<Button
onClick={ () => { order = 'desc'; setAttributes({ order: order }); setContent(); }}
className={order == 'desc' ? 'sorting-button-selected' : ''}
label={__('Sort descending', 'tainacan')}>
<span class="icon">
<i>
<svg width="24" height="24" viewBox="-2 -4 20 20">
<path d="M6.7,3.3H4.2v10.8H2.5V3.3H0L3.3,0L6.7,3.3z M11.6,2.5H8.3v1.7h3.3V2.5z M14.1,7.5H8.3v1.7h5.8V7.5z M16.6,12.5H8.3v1.7 h8.3V12.5z"/>
</svg>
</i>
</span>
</Button>
<Button
onClick={ () => { setContent(); }}
label={__('Search', 'tainacan')}>
<span class="icon">
<i>
<svg width="24" height="24" viewBox="-2 -4 20 20">
<path class="st0" d="M0,5.8C0,5,0.2,4.2,0.5,3.5s0.7-1.3,1.2-1.8s1.1-0.9,1.8-1.2C4.2,0.1,5,0,5.8,0S7.3,0.1,8,0.5
c0.7,0.3,1.3,0.7,1.8,1.2s0.9,1.1,1.2,1.8c0.5,1.2,0.5,2.5,0.2,3.7c0,0.2-0.1,0.4-0.2,0.6c0,0.1-0.2,0.6-0.2,0.6
c0.6,0.6,1.3,1.3,1.9,1.9c0.7,0.7,1.3,1.3,2,2c0,0,0.3,0.2,0.3,0.3c0,0.3-0.1,0.7-0.3,1c-0.2,0.6-0.8,1-1.4,1.2
c-0.1,0-0.6,0.2-0.6,0.1c0,0-4.2-4.2-4.2-4.2c0,0-0.8,0.3-0.8,0.4c-1.3,0.4-2.8,0.5-4.1-0.1c-0.7-0.3-1.3-0.7-1.8-1.2
C1.2,9.3,0.8,8.7,0.5,8S0,6.6,0,5.8z M1.6,5.8c0,0.4,0.1,0.9,0.2,1.3C2.1,8.2,3,9.2,4.1,9.6c0.5,0.2,1,0.3,1.6,0.3
c0.6,0,1.1-0.1,1.6-0.3C8.7,9,9.7,7.6,9.8,6c0.1-1.5-0.6-3.1-2-3.9c-0.9-0.5-2-0.6-3-0.4C4.6,1.8,4.4,1.9,4.1,2
c-0.5,0.2-1,0.5-1.4,0.9C2,3.7,1.6,4.7,1.6,5.8z"/>
</svg>
</i>
</span>
</Button>
<input
value={ searchString }
onChange={ (value) => { _.debounce(applySearchString(value), 300); } }
type="text"/>
<Button
class="previous-button"
disabled
label={__('Previous page', 'tainacan')}>
<span class="icon">
<i>
<svg
width="30"
height="30"
viewBox="0 2 20 20">
<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
<path
d="M0 0h24v24H0z"
fill="none"/>
</svg>
</i>
</span>
</Button>
<Button
class="next-button"
disabled
label={__('Next page', 'tainacan')}>
<span class="icon">
<i>
<svg
width="30"
height="30"
viewBox="0 2 20 20">
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/>
<path
d="M0 0h24v24H0z"
fill="none"/>
</svg>
</i>
</span>
</Button>
</div>
: null
}
{ !items.length && !isLoading ? (
<Placeholder
className="tainacan-block-placeholder"
icon={(
<img
width={148}
src={ `${tainacan_blocks.base_url}/assets/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="M14,2V4H7v7.24A5.33,5.33,0,0,0,5.5,11a4.07,4.07,0,0,0-.5,0V4A2,2,0,0,1,7,2Zm7,10v8a2,2,0,0,1-2,2H12l1-1-2.41-2.41A5.56,5.56,0,0,0,11,16.53a5.48,5.48,0,0,0-2-4.24V8a2,2,0,0,1,2-2h4Zm-2.52,0L14,7.5V12ZM11,21l-1,1L8.86,20.89,8,20H8l-.57-.57A3.42,3.42,0,0,1,5.5,20a3.5,3.5,0,0,1-.5-7,2.74,2.74,0,0,1,.5,0,3.41,3.41,0,0,1,1.5.34,3.5,3.5,0,0,1,2,3.16,3.42,3.42,0,0,1-.58,1.92L9,19H9l.85.85Zm-4-4.5A1.5,1.5,0,0,0,5.5,15a1.39,1.39,0,0,0-.5.09A1.5,1.5,0,0,0,5.5,18a1.48,1.48,0,0,0,1.42-1A1.5,1.5,0,0,0,7,16.53Z"/>
</svg>
{__('Dynamically list items from a Tainacan items search', 'tainacan')}
</p>
<Button
isPrimary
type="button"
onClick={ () => openDynamicItemsModal() }>
{__('Configure search', 'tainacan')}
</Button>
</Placeholder>
) : null
}
{ isLoading ?
<div class="spinner-container">
<Spinner />
</div> :
<div>
{ layout !== 'mosaic' ? (
<ul
style={{
gridGap: layout == 'grid' ? ((showName ? gridMargin + 24 : gridMargin) + 'px') : 'inherit',
marginTop: showSearchBar || showCollectionHeader ? '-' + (Number(gridMargin)/2) : '0px',
padding: (Number(gridMargin)/4) + 'px',
}}
className={'items-list-edit items-layout-' + layout + (!showName ? ' items-list-without-margin' : '') + (maxColumnsCount ? ' max-columns-count-' + maxColumnsCount : '') }>
{ items }
</ul>
) :
<ResizableBox
size={ {
height: mosaicHeight ? mosaicHeight + (3 * gridMargin) : 280 + (3 * gridMargin),
width: '100%'
} }
minHeight="80"
maxHeight="2000"
minWidth="100%"
maxWidth="100%"
showHandle={ true }
enable={ {
top: false,
right: false,
bottom: true,
left: false,
topRight: false,
bottomRight: true,
bottomLeft: true,
topLeft: false,
} }
onResizeStop={ ( event, direction, elt, delta ) => {
mosaicHeight = delta.height ? parseInt(delta.height) + parseInt(mosaicHeight) : 280;
setAttributes({ mosaicHeight: parseInt(mosaicHeight) });
setContent();
} }
>
<ul
style={{
marginTop: showSearchBar || showCollectionHeader ? '-' + (Number(gridMargin)/2) : '0px',
padding: (Number(gridMargin)/4) + 'px',
minHeight: mosaicHeight + 'px'
}}
className={'items-list-edit items-layout-' + layout + (!showName ? ' items-list-without-margin' : '')}>
{ items }
</ul>
</ResizableBox>
}
</div>
}
</div>
);
};

View File

@ -0,0 +1,14 @@
const { SVG, Path } = wp.components;
export default (
<SVG
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
height="24px"
width="24px">
<Path
fill="#298596"
d="M14,2V4H7v7.24A5.33,5.33,0,0,0,5.5,11a4.07,4.07,0,0,0-.5,0V4A2,2,0,0,1,7,2Zm7,10v8a2,2,0,0,1-2,2H12l1-1-2.41-2.41A5.56,5.56,0,0,0,11,16.53a5.48,5.48,0,0,0-2-4.24V8a2,2,0,0,1,2-2h4Zm-2.52,0L14,7.5V12ZM11,21l-1,1L8.86,20.89,8,20H8l-.57-.57A3.42,3.42,0,0,1,5.5,20a3.5,3.5,0,0,1-.5-7,2.74,2.74,0,0,1,.5,0,3.41,3.41,0,0,1,1.5.34,3.5,3.5,0,0,1,2,3.16,3.42,3.42,0,0,1-.58,1.92L9,19H9l.85.85Zm-4-4.5A1.5,1.5,0,0,0,5.5,15a1.39,1.39,0,0,0-.5.09A1.5,1.5,0,0,0,5.5,18a1.48,1.48,0,0,0,1.42-1A1.5,1.5,0,0,0,7,16.53Z"/>
</SVG>
);

View File

@ -0,0 +1,55 @@
export default function({ attributes, className }) {
const {
content,
blockId,
collectionId,
showImage,
showName,
layout,
gridMargin,
searchURL,
maxItemsNumber,
order,
showSearchBar,
showCollectionHeader,
showCollectionLabel,
collectionBackgroundColor,
collectionTextColor,
mosaicHeight,
mosaicGridRows,
mosaicGridColumns,
mosaicItemFocalPoint,
mosaicDensity,
maxColumnsCount,
cropImagesToSquare
} = attributes;
return <div
search-url={ searchURL }
className={ className }
collection-id={ collectionId }
show-image={ '' + showImage }
show-name={ '' + showName }
show-search-bar={ '' + showSearchBar }
show-collection-header={ '' + showCollectionHeader }
show-collection-label={ '' + showCollectionLabel }
crop-images-to-square={ '' + cropImagesToSquare }
layout={ layout }
mosaic-height={ mosaicHeight }
mosaic-density={ mosaicDensity }
mosaic-grid-rows={ mosaicGridRows }
mosaic-grid-columns={ mosaicGridColumns }
mosaic-item-focal-point-x={ (mosaicItemFocalPoint && mosaicItemFocalPoint.x ? mosaicItemFocalPoint.x : 0.5) }
mosaic-item-focal-point-y={ (mosaicItemFocalPoint && mosaicItemFocalPoint.y ? mosaicItemFocalPoint.y : 0.5) }
max-columns-count={ maxColumnsCount }
collection-background-color={ collectionBackgroundColor }
collection-text-color={ collectionTextColor }
grid-margin={ gridMargin }
max-items-number={ maxItemsNumber }
order={ order }
tainacan-api-root={ tainacan_blocks.root }
tainacan-base-url={ tainacan_blocks.base_url }
id={ 'wp-block-tainacan-dynamic-items-list_' + blockId }>
{ content }
</div>
};

View File

@ -52,7 +52,7 @@ export default class TermsModal extends React.Component {
temporarySelectedTerms: JSON.parse(JSON.stringify(this.props.selectedTermsObject))
});
if (this.props.existingTaxonomyId != null && this.props.existingTaxonomyId != undefined) {
if (this.props.existingTaxonomyId) {
this.fetchTaxonomy(this.props.existingTaxonomyId);
this.fetchModalTerms(0, this.props.existingTaxonomyId);
} else {
@ -309,7 +309,7 @@ export default class TermsModal extends React.Component {
}
render() {
return this.state.taxonomyId != null && this.state.taxonomyId != undefined ? (
return this.state.taxonomyId ? (
// Terms modal
<Modal
className="wp-block-tainacan-modal"