First steps on implementing static items gutenberg block.

This commit is contained in:
Mateus Machado Luna 2019-03-11 16:34:35 -03:00
parent 6846501a5f
commit 43283e1605
8 changed files with 1389 additions and 4 deletions

View File

@ -214,4 +214,225 @@
padding: 16px 16px 0 16px;
margin: 0 -16px; }
.wp-block-tainacan-items-list {
margin: 1rem 0px; }
.wp-block-tainacan-items-list .components-spinner {
position: absolute;
right: 0; }
.wp-block-tainacan-items-list .block-control {
display: flex;
flex-direction: row;
justify-content: center; }
.wp-block-tainacan-items-list ul.items-list.items-layout-grid,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-grid {
padding: 0;
display: -ms-grid;
display: grid;
grid-template-columns: repeat(auto-fill, 220px);
grid-gap: 0px;
justify-content: space-evenly;
list-style-type: none; }
.wp-block-tainacan-items-list ul.items-list.items-layout-grid li.item-list-item,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-grid li.item-list-item {
position: relative;
display: block;
margin: 12px 12px 24px 12px;
margin-bottom: 12px;
width: 185px; }
.wp-block-tainacan-items-list ul.items-list.items-layout-grid li.item-list-item a,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-grid li.item-list-item a {
color: #454647;
font-weight: bold; }
.wp-block-tainacan-items-list ul.items-list.items-layout-grid li.item-list-item img,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-grid li.item-list-item img {
height: auto;
width: 185px;
min-width: 185px;
padding: 0px;
margin-bottom: 10px; }
.wp-block-tainacan-items-list ul.items-list.items-layout-grid li.item-list-item a.item-without-title span,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-grid li.item-list-item a.item-without-title span {
display: none; }
.wp-block-tainacan-items-list ul.items-list.items-layout-grid li.item-list-item:hover a,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-grid li.item-list-item:hover a {
color: #454647;
text-decoration: none; }
.wp-block-tainacan-items-list ul.items-list-edit li.item-list-item {
display: flex;
align-items: flex-start; }
.wp-block-tainacan-items-list ul.items-list-edit li.item-list-item 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: -12px;
justify-content: center; }
.wp-block-tainacan-items-list ul.items-list-edit li.item-list-item:hover button {
visibility: visible;
opacity: 1;
right: 0px;
transition: opacity linear 0.15s, right linear 0.15s; }
@media only screen and (max-width: 498px) {
.wp-block-tainacan-items-list ul.items-list.items-layout-grid,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-grid {
grid-template-columns: repeat(auto-fill, 100%); }
.wp-block-tainacan-items-list ul.items-list.items-layout-grid li.item-list-item,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-grid li.item-list-item {
width: 100%; }
.wp-block-tainacan-items-list ul.items-list.items-layout-grid li.item-list-item img,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-grid li.item-list-item img {
width: 100%; } }
.wp-block-tainacan-items-list ul.items-list.items-layout-list,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-list {
padding: 0;
display: block;
list-style-type: none; }
.wp-block-tainacan-items-list ul.items-list.items-layout-list li.item-list-item,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-list li.item-list-item {
position: relative;
display: inline-block;
margin: 12px 12px 24px 12px;
margin-bottom: 12px;
min-height: 54px;
min-width: 22%;
width: 22%; }
.wp-block-tainacan-items-list ul.items-list.items-layout-list li.item-list-item a,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-list li.item-list-item a {
color: #454647;
display: flex;
align-items: center;
height: 54px; }
.wp-block-tainacan-items-list ul.items-list.items-layout-list li.item-list-item img,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-list li.item-list-item img {
height: auto;
width: 54px;
min-width: 54px;
padding: 0px;
margin-right: 20px; }
.wp-block-tainacan-items-list ul.items-list.items-layout-list li.item-list-item a.item-without-image img,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-list li.item-list-item a.item-without-image img {
display: none; }
.wp-block-tainacan-items-list ul.items-list.items-layout-list li.item-list-item:hover a,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-list li.item-list-item:hover a {
color: #454647;
text-decoration: none; }
.wp-block-tainacan-items-list ul.items-list-edit li.item-list-item 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: -12px;
justify-content: center; }
.wp-block-tainacan-items-list ul.items-list-edit li.item-list-item:hover button {
visibility: visible;
opacity: 1;
right: 0px;
transition: opacity linear 0.15s, right linear 0.15s; }
@media only screen and (max-width: 1600px) {
.wp-block-tainacan-items-list ul.items-list.items-layout-list li.item-list-item,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-list li.item-list-item {
min-width: 30%;
width: 30%; } }
@media only screen and (max-width: 1024px) {
.wp-block-tainacan-items-list ul.items-list.items-layout-list li.item-list-item,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-list li.item-list-item {
min-width: 45%;
width: 45%; } }
@media only screen and (max-width: 768px) {
.wp-block-tainacan-items-list ul.items-list.items-layout-list li.item-list-item,
.wp-block-tainacan-items-list ul.items-list-edit.items-layout-list li.item-list-item {
min-width: 100%;
width: 100%; } }
.wp-block-tainacan-items-modal {
width: 50%; }
@media only screen and (max-width: 1024px) {
.wp-block-tainacan-items-modal {
width: 75%; } }
@media only screen and (max-width: 768px) {
.wp-block-tainacan-items-modal {
width: 100%; } }
.wp-block-tainacan-items-modal .components-spinner {
position: absolute;
right: 5%;
bottom: 84px; }
.wp-block-tainacan-items-modal .modal-items-search-area {
display: flex;
justify-content: center;
margin-bottom: 24px; }
.wp-block-tainacan-items-modal .modal-items-search-area .components-base-control {
width: 60%; }
@media only screen and (max-width: 1024px) {
.wp-block-tainacan-items-modal .modal-items-search-area .components-base-control {
width: 95%; } }
.wp-block-tainacan-items-modal .modal-items-search-area .components-base-control label {
text-align: center; }
.wp-block-tainacan-items-modal .modal-items-list,
.wp-block-tainacan-items-modal .modal-collections-list .components-base-control__field {
padding: 0;
display: -ms-grid;
display: grid;
grid-template-columns: repeat(auto-fill, 250px);
grid-gap: 0px;
justify-content: space-evenly;
list-style-type: none;
margin: 12px;
max-height: 50vh;
overflow-y: auto; }
.wp-block-tainacan-items-modal .modal-items-list .components-base-control,
.wp-block-tainacan-items-modal .modal-collections-list .components-base-control__field .components-base-control {
overflow: hidden; }
.wp-block-tainacan-items-modal .modal-items-list .modal-items-list-item,
.wp-block-tainacan-items-modal .modal-items-list .components-radio-control__option,
.wp-block-tainacan-items-modal .modal-collections-list .components-base-control__field .modal-items-list-item,
.wp-block-tainacan-items-modal .modal-collections-list .components-base-control__field .components-radio-control__option {
display: flex;
justify-content: flex-start; }
.wp-block-tainacan-items-modal .modal-items-list .modal-items-list-item img,
.wp-block-tainacan-items-modal .modal-items-list .components-radio-control__option img,
.wp-block-tainacan-items-modal .modal-collections-list .components-base-control__field .modal-items-list-item img,
.wp-block-tainacan-items-modal .modal-collections-list .components-base-control__field .components-radio-control__option img {
width: 24px;
height: 24px;
margin-right: 10px; }
.wp-block-tainacan-items-modal .modal-items-list .modal-items-list-item label,
.wp-block-tainacan-items-modal .modal-items-list .components-radio-control__option label,
.wp-block-tainacan-items-modal .modal-collections-list .components-base-control__field .modal-items-list-item label,
.wp-block-tainacan-items-modal .modal-collections-list .components-base-control__field .components-radio-control__option label {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: inline-block;
max-width: 85%; }
@media only screen and (max-width: 768px) {
.wp-block-tainacan-items-modal .modal-items-list .modal-items-list-item label,
.wp-block-tainacan-items-modal .modal-items-list .components-radio-control__option label,
.wp-block-tainacan-items-modal .modal-collections-list .components-base-control__field .modal-items-list-item label,
.wp-block-tainacan-items-modal .modal-collections-list .components-base-control__field .components-radio-control__option label {
max-width: 80%; } }
.wp-block-tainacan-items-modal .modal-items-loadmore-section {
display: flex;
align-items: baseline;
justify-content: center; }
.wp-block-tainacan-items-modal .modal-items-loadmore-section p {
color: #555758;
margin-right: 12px; }
.wp-block-tainacan-items-modal .modal-items-footer {
border-top: 1px solid #e2e4e7;
display: flex;
align-items: baseline;
justify-content: space-between;
padding: 16px 16px 0 16px;
margin: 0 -16px; }
/*# sourceMappingURL=tainacan-gutenberg-blocks-style.css.map */

File diff suppressed because one or more lines are too long

View File

@ -15,6 +15,7 @@ function tainacan_blocks_initialize() {
function tainacan_blocks_add_gutenberg_blocks_actions() {
add_action('init', 'tainacan_blocks_register_tainacan_items_grid');
add_action('init', 'tainacan_blocks_register_tainacan_terms_list');
add_action('init', 'tainacan_blocks_register_tainacan_items_list');
add_action('init', 'tainacan_blocks_add_plugin_settings');
@ -94,6 +95,29 @@ function tainacan_blocks_register_tainacan_terms_list(){
}
}
function tainacan_blocks_register_tainacan_items_list(){
global $TAINACAN_BASE_URL;
wp_register_script(
'items-list',
$TAINACAN_BASE_URL . '/assets/gutenberg_items_list-components.js',
array('wp-blocks', 'wp-element', 'wp-components', 'wp-editor')
);
wp_register_style(
'items-list',
$TAINACAN_BASE_URL . '/assets/css/tainacan-gutenberg-blocks-style.css',
array('wp-edit-blocks')
);
if(function_exists('register_block_type')) {
register_block_type( 'tainacan/items-list', array(
'editor_script' => 'items-list',
'style' => 'items-list'
) );
}
}
function tainacan_blocks_get_plugin_js_settings(){
global $TAINACAN_BASE_URL;
@ -112,4 +136,5 @@ function tainacan_blocks_add_plugin_settings() {
wp_localize_script( 'items-grid', 'tainacan_plugin', $settings );
wp_localize_script( 'terms-list', 'tainacan_plugin', $settings );
wp_localize_script( 'items-list', 'tainacan_plugin', $settings );
}

View File

@ -1,2 +1,3 @@
@import 'tainacan-items/items-grid/items-grid';
@import 'tainacan-terms/terms-list/terms-list';
@import 'tainacan-items/items-list/items-list';

View File

@ -0,0 +1,863 @@
const { registerBlockType } = wp.blocks;
const { __ } = wp.i18n;
const { TextControl, IconButton, Button, Modal, CheckboxControl, RadioControl, Spinner, ToggleControl, Placeholder, Toolbar } = wp.components;
const { InspectorControls, BlockControls } = wp.editor;
import tainacan from '../../api-client/axios.js';
import qs from 'qs';
import axios from 'axios';
registerBlockType('tainacan/items-list', {
title: __('Tainacan Items List', 'tainacan'),
icon:
<svg width="24" height="24" viewBox="0 -2 12 16">
<path
d="M8.8,1.2H1.2V10H0V1.2C0,0.6,0.6,0,1.2,0h7.5V1.2z M3.8,2.5c-0.7,0-1.2,0.6-1.2,1.3v8.8c0,0.7,0.6,1.2,1.2,1.2h6.9
c0.7,0,1.2-0.6,1.2-1.2V6.3L8.1,2.5H3.8z M7.5,3.4L11,6.9H7.5V3.4z"/>
</svg>,
category: 'tainacan-blocks',
keywords: [ __( 'Tainacan', 'tainacan' ), __( 'items', 'tainacan' ), __( 'collection', 'tainacan' ) ],
attributes: {
selectedItemsObject: {
type: 'array',
source: 'query',
selector: 'a',
query: {
id: {
type: 'string',
source: 'attribute',
attribute: 'id'
},
url: {
type: 'string',
source: 'attribute',
attribute: 'href'
},
title: {
type: 'string',
source: 'text'
},
thumbnail: {
source: 'query',
selector: 'img',
query: {
src: {
source: 'attribute',
attribute: 'src'
},
alt: {
source: 'attribute',
attribute: 'alt'
},
}
},
},
default: []
},
content: {
type: 'array',
source: 'children',
selector: 'div'
},
itemsPerPage: {
type: Number,
default: 24
},
query: {
type: Object,
default: {}
},
collectionId: {
type: String,
default: undefined
},
temporaryCollectionId: {
type: String,
default: ''
},
isLoadingCollections: {
type: Boolean,
default: false
},
isLoadingItems: {
type: Boolean,
default: false
},
collections: {
type: Array,
default: []
},
items: {
type: Array,
default: []
},
selectedItemsHTML: {
type: Array,
default: []
},
temporarySelectedItems: {
type: Array,
default: []
},
searchItemName: {
type: String,
default: ''
},
collectionName: {
type: String,
default: ''
},
showImage: {
type: Boolean,
default: true
},
showName: {
type: Boolean,
default: true
},
layout: {
type: String,
default: 'grid'
},
isModalOpen: {
type: Boolean,
default: false
},
modalItems: {
type: Array,
default: []
},
totalModalItems: {
type: Number,
default: 0
},
modalCollections: {
type: Array,
default: []
},
totalModalCollections: {
type: Number,
default: 0
},
collectionPage: {
type: Number,
default: 1
},
itemsPage: {
type: Number,
default: 1
},
searchCollectionName: {
type: String,
default: ''
},
itemsRequestSource: {
type: Object,
default: undefined
},
collectionsRequestSource: {
type: Object,
default: undefined
}
},
supports: {
align: ['full', 'wide'],
html: false,
},
edit({ attributes, setAttributes, className, isSelected }){
let {
selectedItemsObject,
selectedItemsHTML,
temporarySelectedItems,
items,
content,
searchItemName,
collectionId,
collectionName,
temporaryCollectionId,
isLoadingItems,
isLoadingCollections,
collections,
modalCollections,
totalModalCollections,
searchCollectionName,
collectionPage,
showImage,
showName,
layout,
isModalOpen,
modalItems,
totalModalItems,
itemsPerPage,
itemsPage,
itemsRequestSource,
collectionsRequestSource
} = attributes;
function prepareItem(item) {
return (
<li
key={ item.id }
className="item-list-item">
<IconButton
onClick={ () => removeItemOfId(item.id) }
icon="no-alt"
label={__('Remove', 'tainacan')}/>
<a
id={ isNaN(item.id) ? item.id : 'item-id-' + item.id }
href={ item.url }
target="_blank"
className={ (!showName ? 'item-without-title' : '') + ' ' + (!showImage ? 'item-without-image' : '') }>
<img
src={ item.thumbnail && item.thumbnail[0] && item.thumbnail[0].src ? item.thumbnail[0].src : `${tainacan_plugin.base_url}/admin/images/placeholder_square.png`}
alt={ item.thumbnail && item.thumbnail[0] ? item.thumbnail[0].alt : item.title }/>
<span>{ item.title ? item.title : '' }</span>
</a>
</li>
);
}
function renderCollectionModalContent() {
return (
<Modal
className="wp-block-tainacan-items-modal"
title={__('Select a collection to fetch items from', 'tainacan')}
onRequestClose={ () => setAttributes( { isModalOpen: false } ) }
contentLabel={__('Select items', 'tainacan')}>
<div>
<div className="modal-items-search-area">
<TextControl
label={__('Search for a collection', 'tainacan')}
value={ searchCollectionName }
onChange={(value) => {
setAttributes({
searchCollectionName: value
});
fetchCollections(value);
}}/>
</div>
{(
searchCollectionName != '' ? (
collections.length > 0 ?
(
<div>
<div className="modal-collections-list">
{
<RadioControl
selected={ temporaryCollectionId }
options={
collections.map((collection) => {
return { label: collection.name, value: '' + collection.id }
})
}
onChange={ ( aCollectionId ) => {
temporaryCollectionId = aCollectionId;
setAttributes({ temporaryCollectionId: temporaryCollectionId });
} } />
}
</div>
{ isLoadingCollections ? <Spinner/> : null }
</div>
) :
isLoadingCollections ? (
<Spinner />
) :
<div className="modal-items-loadmore-section">
<p>{ __('Sorry, no collection found.', 'tainacan') }</p>
</div>
):
modalCollections.length > 0 ?
(
<div>
<div className="modal-collections-list">
{
<RadioControl
selected={ temporaryCollectionId }
options={
modalCollections.map((collection) => {
return { label: collection.name, value: '' + collection.id }
})
}
onChange={ ( aCollectionId ) => {
temporaryCollectionId = aCollectionId;
setAttributes({ temporaryCollectionId: temporaryCollectionId });
} } />
}
{ isLoadingItems ? <Spinner/> : null }
</div>
<div className="modal-items-loadmore-section">
<p>{ __('Showing', 'tainacan') + " " + modalCollections.length + " " + __('of', 'tainacan') + " " + totalModalCollections + " " + __('collections', 'tainacan') + "."}</p>
{
modalCollections.length < totalModalCollections ? (
<Button
isDefault
isSmall
onClick={ () => fetchModalCollections() }>
{__('Load more', 'tainacan')}
</Button>
) : null
}
</div>
</div>
) : isLoadingCollections ? <Spinner/> :
<div className="modal-items-loadmore-section">
<p>{ __('Sorry, no collection found.', 'tainacan') }</p>
</div>
)}
<div className="modal-items-footer">
<Button
isDefault
onClick={ () => {
isModalOpen = false;
setAttributes({ isModalOpen: isModalOpen })
}}>
{__('Cancel', 'tainacan')}
</Button>
<Button
isPrimary
disabled={ temporaryCollectionId == undefined || temporaryCollectionId == null || temporaryCollectionId == ''}
onClick={ () => selectCollection(temporaryCollectionId) }>
{__('Select items', 'tainacan')}
</Button>
</div>
</div>
</Modal>
);
}
function renderItemsModalContent() {
return (
<Modal
className="wp-block-tainacan-items-modal"
title={__('Select the desired items for collection ' + collectionName, 'tainacan')}
onRequestClose={ () => setAttributes( { isModalOpen: false } ) }
contentLabel={__('Select items', 'tainacan')}>
<div>
<div className="modal-items-search-area">
<TextControl
label={__('Search for a item', 'tainacan')}
value={ searchItemName }
onInput={(value) => {
setAttributes({
searchItemName: value.target.value
});
}}
onChange={(value) => fetchItems(value)}/>
</div>
{(
searchItemName != '' ? (
items.length > 0 ?
(
<div>
<ul className="modal-items-list">
{
items.map((item) =>
<li
key={ item.id }
className="modal-items-list-item">
{ item.thumbnail && showImage ?
<img
aria-hidden
src={ item.thumbnail && item.thumbnail[0] && item.thumbnail[0].src ? item.thumbnail[0].src : `${tainacan_plugin.base_url}/admin/images/placeholder_square.png`}
alt={ item.thumbnail && item.thumbnail[0] ? item.thumbnail[0].alt : item.title }/>
: null
}
<CheckboxControl
label={ item.title }
checked={ isTemporaryItemSelected(item.id) }
onChange={ ( isChecked ) => { toggleSelectTemporaryItem(item, isChecked) } }
/>
</li>
)
}
</ul>
{ isLoadingItems ? <Spinner/> : null }
</div>
)
: isLoadingItems ? <Spinner/> :
<div className="modal-items-loadmore-section">
<p>{ __('Sorry, no items found.', 'tainacan') }</p>
</div>
) :
modalItems.length > 0 ?
(
<div>
<ul className="modal-items-list">
{
modalItems.map((item) =>
<li
key={ item.id }
className="modal-items-list-item">
{ item.thumbnail && showImage ?
<img
aria-hidden
src={ item.thumbnail && item.thumbnail[0] && item.thumbnail[0].src ? item.thumbnail[0].src : `${tainacan_plugin.base_url}/admin/images/placeholder_square.png`}
alt={ item.thumbnail && item.thumbnail[0] ? item.thumbnail[0].alt : item.title }/>
: null
}
<CheckboxControl
label={ item.title }
checked={ isTemporaryItemSelected(item.id) }
onChange={ ( isChecked ) => { toggleSelectTemporaryItem(item, isChecked) } } />
</li>
)
}
{ isLoadingItems ? <Spinner/> : null }
</ul>
<div className="modal-items-loadmore-section">
<p>{ __('Showing', 'tainacan') + " " + modalItems.length + " " + __('of', 'tainacan') + " " + totalModalItems + " " + __('items', 'tainacan') + "."}</p>
{
modalItems.length < totalModalItems ? (
<Button
isDefault
isSmall
onClick={ () => fetchModalItems() }>
{__('Load more', 'tainacan')}
</Button>
) : null
}
</div>
</div>
) : isLoadingItems ? <Spinner /> :
<div className="modal-items-loadmore-section">
<p>{ __('Sorry, no items found.', 'tainacan') }</p>
</div>
)}
<div className="modal-items-footer">
<Button
isDefault
onClick={ () => resetCollections() }>
{__('Switch collection', 'tainacan')}
</Button>
<Button
isPrimary
onClick={ () => applySelectedItems() }>
{__('Finish', 'tainacan')}
</Button>
</div>
</div>
</Modal>
);
}
function setContent(){
selectedItemsHTML = [];
for (let i = 0; i < selectedItemsObject.length; i++)
selectedItemsHTML.push(prepareItem(selectedItemsObject[i]));
setAttributes({
content: (
<ul className={'items-list items-layout-' + layout}>{ selectedItemsHTML }</ul>
),
selectedItemsHTML: selectedItemsHTML
});
}
function fetchCollections(name) {
if (collectionsRequestSource != undefined)
collectionsRequestSource.cancel('Previous collections search canceled.');
collectionsRequestSource = axios.CancelToken.source();
setAttributes({
collectionsRequestSource: collectionsRequestSource
})
isLoadingCollections = true;
collections = [];
items = []
setAttributes({
isLoadingCollections: isLoadingCollections,
collections: collections,
items: items
});
let endpoint = '/collections/?perpage=' + itemsPerPage;
if (name != undefined && name != '')
endpoint += '&search=' + name;
tainacan.get(endpoint, { cancelToken: collectionsRequestSource.token })
.then(response => {
collections = response.data.map((collection) => ({ name: collection.name, id: collection.id + '' }));
isLoadingCollections = false;
setAttributes({
isLoadingCollections: isLoadingCollections,
collections: collections
});
return collections;
})
.catch(error => {
console.log('Error trying to fetch collections: ' + error);
});
}
function fetchModalCollections() {
if (collectionPage <= 1)
modalCollections = [];
let endpoint = '/collections/?perpage=' + itemsPerPage + '&paged=' + collectionPage;
collectionPage++;
isLoadingCollections = true;
setAttributes({
isLoadingCollections: isLoadingCollections,
collectionPage: collectionPage,
modalCollections: modalCollections
});
tainacan.get(endpoint)
.then(response => {
for (let collection of response.data) {
modalCollections.push({
name: collection.name,
id: collection.id
});
}
isLoadingCollections = false;
totalModalCollections = response.headers['x-wp-total'];
setAttributes({
isLoadingCollections: isLoadingCollections,
modalCollections: modalCollections,
totalModalCollections: totalModalCollections
});
return modalCollections;
})
.catch(error => {
console.log('Error trying to fetch collections: ' + error);
});
}
function fetchItems(title) {
if (itemsRequestSource != undefined)
itemsRequestSource.cancel('Previous items search canceled.');
itemsRequestSource = axios.CancelToken.source();
isLoadingItems = true;
setAttributes({
itemsRequestSource: itemsRequestSource,
isLoadingItems: isLoadingItems
});
let endpoint = '/collection/'+ collectionId + '/items/?perpage=' + itemsPerPage;
if (title != undefined && title != '')
endpoint += '&search=' + title;
tainacan.get(endpoint, { cancelToken: itemsRequestSource.token })
.then(response => {
items = response.data.map((item) => ({
title: item.title,
id: item.id,
url: item.url,
thumbnail: [{
src: item.thumbnail['tainacan-medium'] != undefined ? item.thumbnail['tainacan-medium'][0] : item.thumbnail['medium'][0],
alt: item.title
}],
description: item.description
}));
setAttributes({
isLoadingItems: isLoadingItems,
items: items
});
return items;
})
.catch(error => {
console.log('Error trying to fetch items: ' + error);
});
}
function fetchModalItems() {
if (itemsPage <= 1)
modalItems = [];
let endpoint = '/collection/'+ collectionId + '/items/?&perpage=' + itemsPerPage + '&paged=' + itemsPage;
isLoadingItems = true;
itemsPage++;
setAttributes({
isLoadingItems: isLoadingItems,
modalItems: modalItems,
itemsPage: itemsPage
});
tainacan.get(endpoint)
.then(response => {
for (let item of response.data) {
modalItems.push({
title: item.title,
id: item.id,
url: item.url,
thumbnail: [{
src: item.thumbnail['tainacan-medium'] != undefined ? item.thumbnail['tainacan-medium'][0] : item.thumbnail['medium'][0],
alt: item.title
}],
description: item.description
});
}
isLoadingItems = false;
totalModalItems = response.headers['x-wp-total'];
setAttributes({
isLoadingItems: isLoadingItems,
modalItems: modalItems,
totalModalItems: totalModalItems
});
return modalItems;
})
.catch(error => {
console.log('Error trying to fetch items: ' + error);
});
}
function resetCollections() {
collectionId = null;
collectionPage = 1;
setAttributes({
collectionId: collectionId,
collectionPage: collectionPage
});
fetchModalCollections();
}
function openItemsModal() {
temporarySelectedItems = JSON.parse(JSON.stringify(selectedItemsObject));
if (collectionId != null && collectionId != undefined) {
fetchCollection();
itemsPage = 1;
fetchModalItems();
} else {
collectionPage = 1;
fetchModalCollections()
}
setAttributes( {
isModalOpen: true,
items: [],
temporarySelectedItems: temporarySelectedItems
} );
}
function isTemporaryItemSelected(itemId) {
return temporarySelectedItems.findIndex(item => (item.id == itemId) || (item.id == 'item-id-' + itemId)) >= 0;
}
function toggleSelectTemporaryItem(item, isChecked) {
if (isChecked)
selectTemporaryItem(item);
else
removeTemporaryItemOfId(item.id);
setAttributes({ temporarySelectedItems: temporarySelectedItems });
setContent();
}
function selectCollection(selectedCollectionId) {
collectionId = selectedCollectionId;
setAttributes({
collectionId: collectionId
});
fetchCollection();
fetchModalItems();
setContent();
}
function selectTemporaryItem(item) {
let existingItemIndex = temporarySelectedItems.findIndex((existingItem) => (existingItem.id == 'item-id-' + item.id) || (existingItem.id == item.id));
if (existingItemIndex < 0) {
let itemId = isNaN(item.id) ? item.id : 'item-id-' + item.id;
temporarySelectedItems.push({
id: itemId,
title: item.title,
url: item.url,
thumbnail: item.thumbnail
});
}
}
function removeTemporaryItemOfId(itemId) {
let existingItemIndex = temporarySelectedItems.findIndex((existingItem) => ((existingItem.id == 'item-id-' + itemId) || (existingItem.id == itemId)));
if (existingItemIndex >= 0)
temporarySelectedItems.splice(existingItemIndex, 1);
}
function applySelectedItems() {
selectedItemsObject = JSON.parse(JSON.stringify(temporarySelectedItems));
isModalOpen = false;
setAttributes({
selectedItemsObject: selectedItemsObject,
isModalOpen: isModalOpen
});
setContent();
}
function removeItemOfId(itemId) {
let existingItemIndex = selectedItemsObject.findIndex((existingItem) => ((existingItem.id == 'item-id-' + itemId) || (existingItem.id == itemId)));
if (existingItemIndex >= 0)
selectedItemsObject.splice(existingItemIndex, 1);
setContent();
}
function fetchCollection() {
tainacan.get('/collections/' + collectionId)
.then((response) => {
collectionName = response.data.name;
setAttributes({ collectionName: collectionName });
}).catch(error => {
console.log('Error trying to fetch collection: ' + error);
});
}
function updateLayout(newLayout) {
layout = newLayout;
if (layout == 'grid' && showImage == false)
showImage = true;
if (layout == 'list' && showName == false)
showName = true;
setAttributes({
layout: layout,
showImage: showImage,
showName: showName
});
setContent();
}
// Executed only on the first load of page
if(content && content.length && content[0].type)
setContent();
const layoutControls = [
{
icon: 'grid-view',
title: __( 'Grid View' ),
onClick: () => updateLayout('grid'),
isActive: layout === 'grid',
},
{
icon: 'list-view',
title: __( 'List View' ),
onClick: () => updateLayout('list'),
isActive: layout === 'list',
}
];
return (
<div className={className}>
<div>
<BlockControls>
<Toolbar controls={ layoutControls } />
</BlockControls>
</div>
<div>
<InspectorControls>
<div style={{ marginTop: '24px' }}>
{ layout == 'list' ?
<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();
}
}
/>
: null }
{ layout == 'grid' ?
<ToggleControl
label={__('Name', '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();
}
}
/>
: null }
</div>
</InspectorControls>
</div>
{ isSelected ?
(
<div>
{ isModalOpen && (
collectionId != null && collectionId != undefined ? renderItemsModalContent() : renderCollectionModalContent()
) }
<div className="block-control">
<Button
isPrimary
onClick={ () => openItemsModal() }>
{__('Select items', 'tainacan')}
</Button>
</div>
<hr/>
</div>
) : null
}
{ !selectedItemsHTML.length ? (
<Placeholder
icon={(
<img
width={148}
src={ `${tainacan_plugin.base_url}/admin/images/tainacan_logo_header.svg` }
alt="Tainacan Logo"/>
)}
/>) : null
}
<ul className={'items-list-edit items-layout-' + layout}>{ selectedItemsHTML }</ul>
</div>
);
},
save({ attributes, className }){
const { content } = attributes;
return <div className={className}>{ content }</div>
}
});

View File

@ -0,0 +1,275 @@
.wp-block-tainacan-items-list {
margin: 1rem 0px;
// Spinner
.components-spinner {
position: absolute;
right: 0;
}
// Control region ----------------------------------------------------
.block-control {
display: flex;
flex-direction: row;
justify-content: center;
}
// Grid View Mode ----------------------------------------------------
ul.items-list.items-layout-grid,
ul.items-list-edit.items-layout-grid {
padding: 0;
display: -ms-grid;
display: grid;
grid-template-columns: repeat(auto-fill, 220px);
grid-gap: 0px;
justify-content: space-evenly;
list-style-type: none;
li.item-list-item {
position: relative;
display: block;
margin: 12px 12px 24px 12px;
margin-bottom: 12px;
width: 185px;
a {
color: #454647;
font-weight: bold;
}
img {
height: auto;
width: 185px;
min-width: 185px;
padding: 0px;
margin-bottom: 10px;
}
a.item-without-title span {
display: none;
}
&:hover a {
color: #454647;
text-decoration: none;
}
}
}
ul.items-list-edit li.item-list-item {
display: flex;
align-items: flex-start;
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: -12px;
justify-content: center;
}
&:hover button {
visibility: visible;
opacity: 1;
right: 0px;
transition: opacity linear 0.15s, right linear 0.15s;
}
}
@media only screen and (max-width: 498px) {
ul.items-list.items-layout-grid,
ul.items-list-edit.items-layout-grid {
grid-template-columns: repeat(auto-fill, 100%);
li.item-list-item {
width: 100%;
img { width: 100%; }
}
}
}
// List View Mode ----------------------------------------------------
ul.items-list.items-layout-list,
ul.items-list-edit.items-layout-list {
padding: 0;
display: block;
list-style-type: none;
li.item-list-item {
position: relative;
display: inline-block;
margin: 12px 12px 24px 12px;
margin-bottom: 12px;
min-height: 54px;
min-width: 22%;
width: 22%;
a {
color: #454647;
// overflow: hidden;
// text-overflow: ellipsis;
// white-space: nowrap;
display: flex;
align-items: center;
height: 54px;
}
img {
height: auto;
width: 54px;
min-width: 54px;
padding: 0px;
margin-right: 20px;
}
a.item-without-image img {
display: none;
}
&:hover a {
color: #454647;
text-decoration: none;
}
}
}
ul.items-list-edit li.item-list-item {
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: -12px;
justify-content: center;
}
&:hover button {
visibility: visible;
opacity: 1;
right: 0px;
transition: opacity linear 0.15s, right linear 0.15s;
}
}
@media only screen and (max-width: 1600px) {
ul.items-list.items-layout-list li.item-list-item,
ul.items-list-edit.items-layout-list li.item-list-item {
min-width: 30%;
width: 30%;
}
}
@media only screen and (max-width: 1024px) {
ul.items-list.items-layout-list li.item-list-item,
ul.items-list-edit.items-layout-list li.item-list-item {
min-width: 45%;
width: 45%;
}
}
@media only screen and (max-width: 768px) {
ul.items-list.items-layout-list li.item-list-item,
ul.items-list-edit.items-layout-list li.item-list-item {
min-width: 100%;
width: 100%;
}
}
}
.wp-block-tainacan-items-modal {
width: 50%;
@media only screen and (max-width: 1024px) { width: 75% }
@media only screen and (max-width: 768px) { width: 100%; }
// Spinner
.components-spinner {
position: absolute;
right: 5%;
bottom: 84px;
}
.modal-items-search-area {
display: flex;
justify-content: center;
margin-bottom: 24px;
.components-base-control {
width: 60%;
@media only screen and (max-width: 1024px) { width: 95% }
label {
text-align: center;
}
}
}
.modal-items-list,
.modal-collections-list .components-base-control__field {
padding: 0;
display: -ms-grid;
display: grid;
grid-template-columns: repeat(auto-fill, 250px);
grid-gap: 0px;
justify-content: space-evenly;
list-style-type: none;
margin: 12px;
max-height: 50vh;
overflow-y: auto;
.components-base-control {
overflow: hidden;
}
.modal-items-list-item,
.components-radio-control__option {
display: flex;
justify-content: flex-start;
img {
width: 24px;
height: 24px;
margin-right: 10px;
}
label {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
display: inline-block;
max-width: 85%;
@media only screen and (max-width: 768px) { max-width: 80%; }
}
}
}
.modal-items-loadmore-section {
display: flex;
align-items: baseline;
justify-content: center;
p {
color: #555758;
margin-right: 12px;
}
}
.modal-items-footer {
border-top: 1px solid #e2e4e7;
display: flex;
align-items: baseline;
justify-content: space-between;
padding: 16px 16px 0 16px;
margin: 0 -16px;
}
}

View File

@ -7,7 +7,6 @@ const { TextControl, IconButton, Button, Modal, CheckboxControl, RadioControl, S
const { InspectorControls, BlockControls } = wp.editor;
import tainacan from '../../api-client/axios.js';
import qs from 'qs';
registerBlockType('tainacan/terms-list', {
title: __('Tainacan Terms List', 'tainacan'),
@ -503,7 +502,7 @@ registerBlockType('tainacan/terms-list', {
modalTaxonomies: modalTaxonomies,
totalModalTaxonomies: totalModalTaxonomies
});
return modalTaxonomies;
})
.catch(error => {

View File

@ -10,6 +10,7 @@ module.exports = {
//gutenberg_collections_carousel: './src/gutenberg-blocks/tainacan-collections/collections-carousel/index.js',
gutenberg_items_grid: './src/gutenberg-blocks/tainacan-items/items-grid/index.js',
gutenberg_terms_list: './src/gutenberg-blocks/tainacan-terms/terms-list/index.js',
gutenberg_items_list: './src/gutenberg-blocks/tainacan-items/items-list/index.js',
},
output: {
path: path.resolve(__dirname, './src/assets/'),