Merge branch 'feature/gutenberg-terms-parent' into develop

This commit is contained in:
Mateus Machado Luna 2019-11-19 13:59:39 -03:00
commit a1937bc63f
4 changed files with 524 additions and 18 deletions

View File

@ -10,7 +10,8 @@ document.addEventListener("DOMContentLoaded", () => {
metadatumId: '',
metadatumType: '',
collectionId: '',
collectionSlug: '',
collectionSlug: '',
parentTermId: null,
showImage: true,
showItemsCount: true,
showSearchBar: false,
@ -30,7 +31,8 @@ document.addEventListener("DOMContentLoaded", () => {
metadatumId: this.metadatumId,
metadatumType: this.metadatumType,
collectionId: this.collectionId,
collectionSlug: this.collectionSlug,
collectionSlug: this.collectionSlug,
parentTermId: this.parentTermId,
showImage: this.showImage,
showItemsCount: this.showItemsCount,
showSearchBar: this.showSearchBar,
@ -51,6 +53,7 @@ document.addEventListener("DOMContentLoaded", () => {
this.metadatumType = this.$el.attributes['metadatum-type'] != undefined ? this.$el.attributes['metadatum-type'].value : undefined;
this.collectionId = this.$el.attributes['collection-id'] != undefined ? this.$el.attributes['collection-id'].value : undefined;
this.collectionSlug = this.$el.attributes['collection-slug'] != undefined ? this.$el.attributes['collection-slug'].value : undefined;
this.parentTermId = this.$el.attributes['parent-term-id'] != undefined ? this.$el.attributes['parent-term-id'].value : undefined;
this.showImage = this.$el.attributes['show-image'] != undefined ? this.$el.attributes['show-image'].value == 'true' : true;
this.showItemsCount = this.$el.attributes['show-items-count'] != undefined ? this.$el.attributes['show-items-count'].value == 'true' : true;
this.showSearchBar = this.$el.attributes['show-search-bar'] != undefined ? this.$el.attributes['show-search-bar'].value == 'true' : false;

View File

@ -158,7 +158,8 @@ export default {
metadatumId: String,
metadatumType: String,
collectionId: String,
collectionSlug: String,
collectionSlug: String,
parentTermId: String,
showImage: Boolean,
showItemsCount: Boolean,
showSearchBar: Boolean,
@ -227,7 +228,15 @@ export default {
queryObject.offset = this.offset;
if (this.lastTerm != undefined)
queryObject.last_term = this.lastTerm;
// Set up parentTerm for taxonomies
if (this.parentTermId !== undefined && this.parentTermId !== null && this.parentTermId !== '' && this.metadatumType == 'Taxonomy')
queryObject.parent = this.parentTermId;
else {
delete queryObject.parent;
this.parentTermId = null;
}
// Parameter fo tech entity object with image and url
queryObject['context'] = 'extended';

View File

@ -2,11 +2,12 @@ const { registerBlockType } = wp.blocks;
const { __ } = wp.i18n;
const { RangeControl, Spinner, Button, ToggleControl, Tooltip, Placeholder, Toolbar, PanelBody } = wp.components;
const { BaseControl, RangeControl, Spinner, Button, ToggleControl, Tooltip, Placeholder, Toolbar, PanelBody } = wp.components;
const { InspectorControls, BlockControls } = wp.editor;
import MetadataModal from './metadata-modal.js';
import ParentTermModal from './parent-term-modal.js';
import tainacan from '../../api-client/axios.js';
import axios from 'axios';
import qs from 'qs';
@ -116,6 +117,14 @@ registerBlockType('tainacan/facets-list', {
type: String,
default: undefined
},
parentTerm: {
type: Number,
default: null
},
isParentTermModalOpen: {
type: Boolean,
default: false
}
},
supports: {
align: ['full', 'wide'],
@ -141,7 +150,9 @@ registerBlockType('tainacan/facets-list', {
facetsRequestSource,
maxFacetsNumber,
searchString,
isLoading
isLoading,
parentTerm,
isParentTermModalOpen
} = attributes;
// Obtains block's client id to render it on save function
@ -231,6 +242,14 @@ registerBlockType('tainacan/facets-list', {
setAttributes({ searchString: undefined });
}
// Set up parentTerm for taxonomies
if (parentTerm && parentTerm.id !== undefined && parentTerm.id !== null && parentTerm.id !== '' && metadatumType == 'Taxonomy')
queryObject.parent = parentTerm.id;
else {
delete queryObject.parent;
setAttributes({ parentTerm: null });
}
// Parameter fo tech entity object with image and url
queryObject['context'] = 'extended';
@ -284,6 +303,13 @@ registerBlockType('tainacan/facets-list', {
isModalOpen: isModalOpen
} );
}
function openParentTermModal() {
isParentTermModalOpen = true;
setAttributes( {
isParentTermModalOpen: isParentTermModalOpen
} );
}
function updateLayout(newLayout) {
layout = newLayout;
@ -391,6 +417,25 @@ registerBlockType('tainacan/facets-list', {
max={ 96 }
/>
</div>
{ metadatumType == 'Taxonomy' ?
<div>
<BaseControl
id="parent-term-selection"
label={ (parentTerm && (parentTerm.id === '0' || parentTerm.id === 0)) ? __('Showing only:', 'tainacan') : __('Showing children of:', 'tainacan') }
help="Narrow terms to children of a parent term."
>
<span style={{ fontWeight: 'bold' }}>&nbsp;{ parentTerm && parentTerm.name ? parentTerm.name : __('Any term.', 'tainacan') }</span>
<br />
<Button
style={{ margin: '6px auto 16px auto', display: 'block' }}
id="parent-term-selection"
isPrimary
onClick={ () => openParentTermModal() }>
{__('Select parent term', 'tainacan')}
</Button>
</BaseControl>
</div>
: null}
<hr></hr>
<div>
{ layout == 'list' && (metadatumType == 'Taxonomy' || metadatumType == 'Relationship') ?
@ -497,13 +542,31 @@ registerBlockType('tainacan/facets-list', {
setAttributes({
metadatumId: metadatumId,
metadatumType: metadatumType,
isModalOpen: false
isModalOpen: false,
parentTerm: null
});
setContent();
}}
onCancelSelection={ () => setAttributes({ isModalOpen: false }) }/>
: null
}
{ isParentTermModalOpen ?
<ParentTermModal
existingFacetId={ parentTerm && parentTerm.id ? parentTerm.id : null }
collectionId={ collectionId }
metadatumId={ metadatumId }
onSelectFacet={ (selectedFacet) => {
parentTerm = selectedFacet.id !== null && selectedFacet.id !== '' && selectedFacet.id !== undefined ? selectedFacet : null
setAttributes({
parentTerm: parentTerm,
isParentTermModalOpen: false
});
setContent();
}}
onCancelSelection={ () => setAttributes({ isParentTermModalOpen: false }) }/>
: null
}
{ facets.length ? (
<div className="block-control">
@ -523,7 +586,7 @@ registerBlockType('tainacan/facets-list', {
isPrimary
type="submit"
onClick={ () => openMetadataModal() }>
{__('Configure search', 'tainacan')}
{__('Select facets', 'tainacan')}
</Button>
</div>
): null
@ -580,12 +643,32 @@ registerBlockType('tainacan/facets-list', {
</svg>
{__('List facets from a Tainacan Collection or Repository', 'tainacan')}
</p>
<Button
isPrimary
type="submit"
onClick={ () => openMetadataModal() }>
{__('Select facets', 'tainacan')}
</Button>
{
parentTerm && parentTerm.id && metadatumType == 'Taxonomy'?
<div style={{ display: 'flex' }}>
<Button
isPrimary
type="submit"
onClick={ () => openParentTermModal() }>
{__('Change parent term', 'tainacan')}
</Button>
<p style={{ margin: '0 12px' }}>{__('or', 'tainacan')}</p>
<Button
isPrimary
type="submit"
onClick={ () => openMetadataModal() }>
{__('Change facets source', 'tainacan')}
</Button>
</div>
:
<Button
isPrimary
type="submit"
onClick={ () => openMetadataModal() }>
{__('Select facets', 'tainacan')}
</Button>
}
</Placeholder>
) : null
}
@ -637,7 +720,8 @@ registerBlockType('tainacan/facets-list', {
content,
blockId,
collectionId,
collectionSlug,
collectionSlug,
parentTerm,
showImage,
showItemsCount,
showLoadMore,
@ -649,13 +733,13 @@ registerBlockType('tainacan/facets-list', {
maxFacetsNumber,
showSearchBar,
} = attributes;
return <div
className={ className }
metadatum-id={ metadatumId }
metadatum-type={ metadatumType }
collection-id={ collectionId }
collection-slug={ collectionSlug }
collection-slug={ collectionSlug }
parent-term-id={ parentTerm ? parentTerm.id : null }
show-image={ '' + showImage }
show-items-count={ '' + showItemsCount }
show-search-bar={ '' + showSearchBar }
@ -670,5 +754,139 @@ registerBlockType('tainacan/facets-list', {
id={ 'wp-block-tainacan-facets-list_' + blockId }>
{ content }
</div>
}
},
deprecated: [
{
attributes: {
content: {
type: 'array',
source: 'children',
selector: 'div'
},
collectionId: {
type: String,
default: undefined
},
collectionSlug: {
type: String,
default: undefined
},
facets: {
type: Array,
default: []
},
facetsObject: {
type: Array,
default: []
},
showImage: {
type: Boolean,
default: true
},
showItemsCount: {
type: Boolean,
default: true
},
showLoadMore: {
type: Boolean,
default: false
},
showSearchBar: {
type: Boolean,
value: false
},
layout: {
type: String,
default: 'grid'
},
cloudRate: {
type: Number,
default: 1
},
isModalOpen: {
type: Boolean,
default: false
},
gridMargin: {
type: Number,
default: 0
},
metadatumId: {
type: String,
default: undefined
},
metadatumType: {
type: String,
default: undefined
},
facetsRequestSource: {
type: String,
default: undefined
},
maxFacetsNumber: {
type: Number,
value: undefined
},
isLoading: {
type: Boolean,
value: false
},
isLoadingCollection: {
type: Boolean,
value: false
},
collection: {
type: Object,
value: undefined
},
searchString: {
type: String,
default: undefined
},
blockId: {
type: String,
default: undefined
},
},
save({ attributes, className }){
const {
content,
blockId,
collectionId,
collectionSlug,
showImage,
showItemsCount,
showLoadMore,
layout,
cloudRate,
gridMargin,
metadatumId,
metadatumType,
maxFacetsNumber,
showSearchBar,
} = attributes;
return <div
className={ className }
metadatum-id={ metadatumId }
metadatum-type={ metadatumType }
collection-id={ collectionId }
collection-slug={ collectionSlug }
show-image={ '' + showImage }
show-items-count={ '' + showItemsCount }
show-search-bar={ '' + showSearchBar }
show-load-more={ '' + showLoadMore }
layout={ layout }
cloud-rate={ cloudRate }
grid-margin={ gridMargin }
max-facets-number={ maxFacetsNumber }
tainacan-api-root={ tainacan_plugin.root }
tainacan-base-url={ tainacan_plugin.base_url }
tainacan-site-url={ tainacan_plugin.site_url }
id={ 'wp-block-tainacan-facets-list_' + blockId }>
{ content }
</div>
}
}
]
});

View File

@ -0,0 +1,276 @@
import tainacan from '../../api-client/axios.js';
import axios from 'axios';
const { __ } = wp.i18n;
const { TextControl, Button, Modal, RadioControl, SelectControl, Spinner } = wp.components;
export default class ParentTermModal extends React.Component {
constructor(props) {
super(props);
// Initialize state
this.state = {
metadatumId: '',
facetsPerPage: 3,
facetId: undefined,
isLoadingFacets: false,
modalFacets: [],
totalModalFacets: 0,
offset: 0,
lastTerm: undefined,
temporaryFacetId: '',
searchFacetName: '',
facets: [],
facetsRequestSource: undefined
};
// Bind events
this.selectFacet = this.selectFacet.bind(this);
this.fetchFacets = this.fetchFacets.bind(this);
this.fetchModalFacets = this.fetchModalFacets.bind(this);
}
componentWillMount() {
this.setState({
collectionId: this.props.collectionId,
metadatumId: this.props.metadatumId,
temporaryFacetId: this.props.existingFacetId,
facetId: this.props.existingFacetId,
offset: 0,
lastTerm: undefined
});
this.fetchModalFacets();
}
// COLLECTIONS RELATED --------------------------------------------------
fetchModalFacets() {
let someModalFacets = this.state.modalFacets;
if (this.state.offset == 0)
someModalFacets = [];
let endpoint = '/facets/' + this.props.metadatumId + '?number=' + this.state.facetsPerPage + '&offset=' + this.state.offset;
if (this.state.collectionId)
endpoint = '/collection/' + this.props.collectionId + endpoint;
if (this.state.lastTerm != undefined)
endpoint += 'last_term=' + this.state.lastTerm
this.setState({
isLoadingFacets: true,
modalFacets: someModalFacets
});
tainacan.get(endpoint)
.then(response => {
let otherModalFacets = this.state.modalFacets;
for (let facet of response.data.values) {
otherModalFacets.push({
name: facet.label,
id: facet.value
});
}
this.setState({
isLoadingFacets: false,
modalFacets: otherModalFacets,
totalModalFacets: response.headers['x-wp-total'],
offset: this.state.offset + response.data.values.length,
lastTerm: response.data.last_term
});
return otherModalFacets;
})
.catch(error => {
console.log('Error trying to fetch facets: ' + error);
});
}
selectFacet(selectedFacetId) {
let selectedFacet;
if (selectedFacetId === null || selectedFacetId === '')
selectedFacet = { name: __('Any term.', 'tainacan'), id: null };
else if (selectedFacetId == '0' || selectedFacet == 0)
selectedFacet = { name: __('Root terms', 'tainacan'), id: '0' };
else {
selectedFacet = this.state.modalFacets.find((facet) => facet.id == selectedFacetId)
if (selectedFacet == undefined)
selectedFacet = this.state.facets.find((facet) => facet.id == selectedFacetId)
}
this.setState({
facetId: selectedFacet.id
});
this.props.onSelectFacet(selectedFacet);
}
fetchFacets(name) {
if (this.state.facetsRequestSource != undefined)
this.state.facetsRequestSource.cancel('Previous facets search canceled.');
let aFacetRequestSource = axios.CancelToken.source();
this.setState({
facetsRequestSource: aFacetRequestSource,
isLoadingFacets: true,
facets: [],
metadata: []
});
let endpoint = '/facets/' + this.props.metadatumId + '?number=' + this.state.facetsPerPage;
if (this.state.collectionId)
endpoint = '/collection/' + this.props.collectionId + endpoint;
if (name != undefined && name != '')
endpoint += '&search=' + name;
tainacan.get(endpoint, { cancelToken: aFacetRequestSource.token })
.then(response => {
let someFacets = response.data.values.map((facet) => ({ name: facet.label, id: facet.value + '' }));
this.setState({
isLoadingFacets: false,
facets: someFacets
});
return someFacets;
})
.catch(error => {
console.log('Error trying to fetch facets: ' + error);
});
}
cancelSelection() {
this.setState({
modalFacets: []
});
this.props.onCancelSelection();
}
render() {
return (
// Facets modal
<Modal
className="wp-block-tainacan-modal"
title={__('Select a parent term to fetch facets from', 'tainacan')}
onRequestClose={ () => this.cancelSelection() }
contentLabel={__('Select term', 'tainacan')}>
<div>
<div className="modal-search-area">
<TextControl
label={__('Search for a term', 'tainacan')}
placeholder={ __('Search by term\'s name', 'tainacan') }
value={ this.state.searchFacetName }
onChange={(value) => {
this.setState({
searchFacetName: value
});
_.debounce(this.fetchFacets(value), 300);
}}/>
</div>
{(
this.state.searchFacetName != '' ? (
this.state.facets.length > 0 ?
(
<div>
<div className="modal-radio-list">
{
<RadioControl
selected={ this.state.temporaryFacetId }
options={
this.state.facets.map((facet) => {
return { label: facet.name, value: '' + facet.id }
})
}
onChange={ ( aFacetId ) => {
this.setState({ temporaryFacetId: aFacetId });
} } />
}
</div>
<br/>
</div>
) :
this.state.isLoadingFacets ? (
<Spinner />
) :
<div className="modal-loadmore-section">
<p>{ __('Sorry, no term found.', 'tainacan') }</p>
</div>
):
this.state.modalFacets.length > 0 ?
(
<div>
<div className="modal-radio-list">
<p class="modal-radio-area-label">{__('Non specific term', 'tainacan')}</p>
<RadioControl
className={'repository-radio-option'}
selected={ this.state.temporaryFacetId }
options={ [
{ label: __('Terms children of any term', 'tainacan'), value: '' },
{ label: __('Terms with no parent (root terms)', 'tainacan'), value: '0' }
] }
onChange={ ( aFacetId ) => {
this.setState({ temporaryFacetId: aFacetId});
} } />
<hr/>
<p class="modal-radio-area-label">{__('Terms', 'tainacan')}</p>
<RadioControl
selected={ this.state.temporaryFacetId }
options={
this.state.modalFacets.map((facet) => {
return { label: facet.name, value: '' + facet.id }
})
}
onChange={ ( aFacetId ) => {
this.setState({ temporaryFacetId: aFacetId });
} } />
</div>
<div className="modal-loadmore-section">
<p>{ __('Showing', 'tainacan') + " " + this.state.modalFacets.length + " " + __('of', 'tainacan') + " " + this.state.totalModalFacets + " " + __('terms', 'tainacan') + "."}</p>
{
this.state.modalFacets.length < this.state.totalModalFacets ? (
<Button
isDefault
isSmall
onClick={ () => this.fetchModalFacets() }>
{__('Load more', 'tainacan')}
</Button>
) : null
}
</div>
</div>
) : this.state.isLoadingFacets ? <Spinner/> :
<div className="modal-loadmore-section">
<p>{ __('Sorry, no terms found.', 'tainacan') }</p>
</div>
)}
<div className="modal-footer-area">
<Button
isDefault
onClick={ () => { this.cancelSelection() }}>
{__('Cancel', 'tainacan')}
</Button>
<Button
isPrimary
onClick={ () => { this.selectFacet(this.state.temporaryFacetId) } }>
{__('Select term', 'tainacan')}
</Button>
</div>
</div>
</Modal>
);
}
}