Skip to content

Commit 4f8e3ea

Browse files
committed
Fix gallery block inconsistencies
1 parent 353ffb0 commit 4f8e3ea

File tree

8 files changed

+210
-128
lines changed

8 files changed

+210
-128
lines changed

.eslintrc.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"rules": {
1717
"no-alert": "off",
1818
"no-console": "off",
19+
"no-unused-vars": "off",
1920
"no-nested-ternary": "off",
2021
"jsx-a11y/click-events-have-key-events": "off",
2122
"react-hooks/rules-of-hooks": "error",

css/src/gallery.scss

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@
2525
}
2626
}
2727

28+
.loading-spinner-container {
29+
position: absolute;
30+
width: 100%;
31+
height: 100%;
32+
background-color: rgba(255,255,255,0.8);
33+
top: 0;
34+
left: 0;
35+
display: flex;
36+
align-items: center;
37+
justify-content: center;
38+
}
39+
2840
/* stylelint-disable selector-class-pattern */
2941
.components-placeholder__fieldset {
3042
justify-content: start;

js/src/components/settings-gallery.js

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,35 @@
1-
/*global CLD_THEME_COLORS */
1+
/*global CLD_THEME_COLORS, cloudinaryGalleryConfig */
22

33
import React from 'react';
4+
import Dot from 'dot-object';
45
import { render, useEffect, useState } from '@wordpress/element';
5-
import attributes from '../gallery-block/attributes';
66
import GalleryControls from '../gallery-block/controls';
7-
import { setupAttributesForRendering } from '../gallery-block/utils';
87

9-
delete attributes.cloudName;
10-
delete attributes.mediaAssets;
8+
import {
9+
setupAttributesForRendering,
10+
toBlockAttributes,
11+
} from '../gallery-block/utils';
12+
13+
const { cloudName, mediaAssets, ...attributes } = toBlockAttributes(
14+
new Dot( '_' ).dot( cloudinaryGalleryConfig )
15+
);
1116

1217
const parsedAttrs = {};
1318
Object.keys( attributes ).forEach( ( attr ) => {
1419
parsedAttrs[ attr ] = attributes[ attr ]?.default;
1520
} );
1621

17-
function galleryWidgetConfig( config ) {
18-
return {
19-
cloudName: 'demo',
20-
...config,
21-
mediaAssets: [
22-
{
23-
tag: 'shoes_product_gallery_demo',
24-
mediaType: 'image',
25-
},
26-
],
27-
container: '.gallery-preview',
28-
};
29-
}
22+
const galleryWidgetConfig = ( config ) => ( {
23+
cloudName: 'demo',
24+
...config,
25+
mediaAssets: [
26+
{
27+
tag: 'shoes_product_gallery_demo',
28+
mediaType: 'image',
29+
},
30+
],
31+
container: '.gallery-preview',
32+
} );
3033

3134
const StatefulGalleryControls = () => {
3235
const [ statefulAttrs, setStatefulAttrs ] = useState( parsedAttrs );

js/src/gallery-block/attributes.js

Lines changed: 0 additions & 48 deletions
This file was deleted.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
{
2+
"aspectRatio": {
3+
"type": "string"
4+
},
5+
"navigation": {
6+
"type": "string"
7+
},
8+
"zoom": {
9+
"type": "boolean"
10+
},
11+
"carouselLocation": {
12+
"type": "string"
13+
},
14+
"carouselOffset": {
15+
"type": "number"
16+
},
17+
"carouselStyle": {
18+
"type": "string"
19+
},
20+
"displayProps_mode": {
21+
"type": "string"
22+
},
23+
"displayProps_columns": {
24+
"type": "number"
25+
},
26+
"indicatorProps_shape": {
27+
"type": "string"
28+
},
29+
"themeProps_primary": {
30+
"type": "string"
31+
},
32+
"themeProps_onPrimary": {
33+
"type": "string"
34+
},
35+
"themeProps_active": {
36+
"type": "string"
37+
},
38+
"zoomProps_type": {
39+
"type": "string"
40+
},
41+
"zoomProps_viewerPosition": {
42+
"type": "string"
43+
},
44+
"zoomProps_trigger": {
45+
"type": "string"
46+
},
47+
"thumbnailProps_width": {
48+
"type": "number"
49+
},
50+
"thumbnailProps_height": {
51+
"type": "number"
52+
},
53+
"thumbnailProps_navigationShape": {
54+
"type": "string"
55+
},
56+
"thumbnailProps_selectedStyle": {
57+
"type": "string"
58+
},
59+
"thumbnailProps_selectedBorderPosition": {
60+
"type": "string"
61+
},
62+
"thumbnailProps_selectedBorderWidth": {
63+
"type": "number"
64+
},
65+
"thumbnailProps_mediaSymbolShape": {
66+
"type": "string"
67+
},
68+
"cloudName": {
69+
"type": "string"
70+
},
71+
"container": {
72+
"type": "string"
73+
},
74+
"selectedImages": {
75+
"type": "array",
76+
"default": []
77+
}
78+
}

js/src/gallery-block/edit.js

Lines changed: 71 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
/* global cloudinaryGalleryApi */
1+
/* global cloudinaryGalleryApi cloudinaryGalleryConfig */
2+
3+
/**
4+
* External dependencies
5+
*/
6+
import Dot from 'dot-object';
27

38
/**
49
* WordPress dependencies
510
*/
611
import { __ } from '@wordpress/i18n';
12+
import { Spinner } from '@wordpress/components';
713
import '@wordpress/components/build-style/style.css';
814
import { useEffect, useMemo, useState } from '@wordpress/element';
915
import { InspectorControls, MediaPlaceholder } from '@wordpress/block-editor';
@@ -16,51 +22,72 @@ import Controls from './controls';
1622
import { ALLOWED_MEDIA_TYPES } from './options';
1723
import { generateId, setupAttributesForRendering, showNotice } from './utils';
1824

25+
const dot = new Dot( '_' );
26+
1927
const PLACEHOLDER_TEXT = __(
2028
'Drag images, upload new ones or select files from your library.',
2129
'cloudinary'
2230
);
2331

24-
function galleryWidgetConfig( config, container ) {
25-
return {
26-
cloudName: CLDN.mloptions.cloud_name,
27-
...config,
28-
container: '.' + container,
29-
zoom: false,
30-
};
31-
}
32+
const galleryWidgetConfig = ( config, container ) => ( {
33+
...config,
34+
container: '.' + container,
35+
zoom: false,
36+
} );
3237

3338
const Edit = ( { setAttributes, attributes, className, isSelected } ) => {
3439
const [ errorMessage, setErrorMessage ] = useState( null );
40+
const [ loading, setLoading ] = useState( false );
41+
42+
const preparedAttributes = useMemo( () => {
43+
const defaultAttrs = {};
44+
45+
// eslint-disable-next-line no-unused-vars
46+
const { container, ...flattenedAttrs } = dot.dot(
47+
cloudinaryGalleryConfig
48+
);
49+
50+
Object.keys( flattenedAttrs ).forEach( ( attr ) => {
51+
if ( ! attributes[ attr ] ) {
52+
defaultAttrs[ attr ] = flattenedAttrs[ attr ];
53+
}
54+
} );
55+
56+
return { ...attributes, ...defaultAttrs };
57+
}, [ attributes ] );
3558

3659
const getAttachmentIds = useMemo( () => {
3760
if ( ! attributes.selectedImages.length ) {
3861
return [];
3962
}
4063

41-
return attributes.selectedImages.map( ( image ) => ( {
42-
id: image.attachmentId,
64+
return attributes.selectedImages.map( ( { attachmentId } ) => ( {
65+
id: attachmentId,
4366
} ) );
4467
}, [ attributes ] );
4568

46-
const onSelect = ( images ) => {
47-
fetch( cloudinaryGalleryApi.endpoint, {
48-
method: 'POST',
49-
body: JSON.stringify( { images } ),
50-
headers: {
51-
'X-WP-Nonce': cloudinaryGalleryApi.nonce,
52-
},
53-
} )
54-
.then( ( res ) => res.json() )
55-
.then( ( selectedImages ) => setAttributes( { selectedImages } ) )
56-
.catch( () =>
57-
setErrorMessage(
58-
__(
59-
'Could not load selected images. Please try again.',
60-
'cloudinary'
61-
)
69+
const onSelect = async ( images ) => {
70+
setLoading( true );
71+
72+
try {
73+
const res = await fetch( cloudinaryGalleryApi.endpoint, {
74+
method: 'POST',
75+
body: JSON.stringify( { images } ),
76+
headers: {
77+
'X-WP-Nonce': cloudinaryGalleryApi.nonce,
78+
},
79+
} );
80+
81+
const selectedImages = await res.json();
82+
setAttributes( { selectedImages } );
83+
} catch {
84+
setErrorMessage(
85+
__(
86+
'Could not load selected images. Please try again.',
87+
'cloudinary'
6288
)
6389
);
90+
}
6491
};
6592

6693
useEffect( () => {
@@ -76,12 +103,6 @@ const Edit = ( { setAttributes, attributes, className, isSelected } ) => {
76103
attributes
77104
);
78105

79-
if ( ! attributes.container ) {
80-
setAttributes( {
81-
container: `${ className }${ generateId( 15 ) }`,
82-
} );
83-
}
84-
85106
try {
86107
gallery = cloudinary.galleryWidget(
87108
galleryWidgetConfig(
@@ -96,13 +117,22 @@ const Edit = ( { setAttributes, attributes, className, isSelected } ) => {
96117
}
97118

98119
gallery.render();
120+
setLoading( false );
99121

100122
return () => gallery.destroy();
101123
}
102124
}, [ errorMessage, attributes, setAttributes, className ] );
103125

104126
const hasImages = !! attributes.selectedImages.length;
105127

128+
if ( ! attributes.container ) {
129+
setAttributes( {
130+
container: `${ className }${ generateId( 15 ) }`,
131+
} );
132+
}
133+
134+
setAttributes( preparedAttributes );
135+
106136
return (
107137
<>
108138
<>
@@ -120,10 +150,16 @@ const Edit = ( { setAttributes, attributes, className, isSelected } ) => {
120150
allowedTypes={ ALLOWED_MEDIA_TYPES }
121151
addToGallery={ hasImages }
122152
isAppender={ hasImages }
123-
onSelect={ onSelect }
153+
onSelect={ ( images ) => onSelect( images ) }
124154
value={ getAttachmentIds }
125155
multiple
126-
/>
156+
>
157+
{ loading && (
158+
<div className="loading-spinner-container">
159+
<Spinner />
160+
</div>
161+
) }
162+
</MediaPlaceholder>
127163
</div>
128164
</>
129165
<InspectorControls>

js/src/gallery-block/index.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,7 @@ import { registerBlockType } from '@wordpress/blocks';
99
*/
1010
import edit from './edit';
1111
import save from './save';
12-
import attributes from './attributes';
13-
14-
attributes.container = { type: 'string' };
12+
import attributes from './attributes.json';
1513

1614
registerBlockType( 'cloudinary/gallery', {
1715
title: __( 'Cloudinary Gallery', 'cloudinary' ),

0 commit comments

Comments
 (0)