1 |
|
2 |
|
3 |
|
4 | import { filter, every, map, some } from 'lodash';
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | import { __ } from '@wordpress/i18n';
|
10 | import { createBlock } from '@wordpress/blocks';
|
11 | import { RichText } from '@wordpress/block-editor';
|
12 | import { mediaUpload } from '@wordpress/editor';
|
13 | import { createBlobURL } from '@wordpress/blob';
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | import { default as edit, defaultColumnsNumber, pickRelevantMediaFiles } from './edit';
|
19 | import icon from './icon';
|
20 |
|
21 | const blockAttributes = {
|
22 | images: {
|
23 | type: 'array',
|
24 | default: [],
|
25 | source: 'query',
|
26 | selector: 'ul.wp-block-gallery .blocks-gallery-item',
|
27 | query: {
|
28 | url: {
|
29 | source: 'attribute',
|
30 | selector: 'img',
|
31 | attribute: 'src',
|
32 | },
|
33 | link: {
|
34 | source: 'attribute',
|
35 | selector: 'img',
|
36 | attribute: 'data-link',
|
37 | },
|
38 | alt: {
|
39 | source: 'attribute',
|
40 | selector: 'img',
|
41 | attribute: 'alt',
|
42 | default: '',
|
43 | },
|
44 | id: {
|
45 | source: 'attribute',
|
46 | selector: 'img',
|
47 | attribute: 'data-id',
|
48 | },
|
49 | caption: {
|
50 | type: 'string',
|
51 | source: 'html',
|
52 | selector: 'figcaption',
|
53 | },
|
54 | },
|
55 | },
|
56 | ids: {
|
57 | type: 'array',
|
58 | default: [],
|
59 | },
|
60 | columns: {
|
61 | type: 'number',
|
62 | },
|
63 | imageCrop: {
|
64 | type: 'boolean',
|
65 | default: true,
|
66 | },
|
67 | linkTo: {
|
68 | type: 'string',
|
69 | default: 'none',
|
70 | },
|
71 | };
|
72 |
|
73 | export const name = 'core/gallery';
|
74 |
|
75 | const parseShortcodeIds = ( ids ) => {
|
76 | if ( ! ids ) {
|
77 | return [];
|
78 | }
|
79 |
|
80 | return ids.split( ',' ).map( ( id ) => (
|
81 | parseInt( id, 10 )
|
82 | ) );
|
83 | };
|
84 |
|
85 | export const settings = {
|
86 | title: __( 'Gallery' ),
|
87 | description: __( 'Display multiple images in a rich gallery.' ),
|
88 | icon,
|
89 | category: 'common',
|
90 | keywords: [ __( 'images' ), __( 'photos' ) ],
|
91 | attributes: blockAttributes,
|
92 | supports: {
|
93 | align: true,
|
94 | },
|
95 |
|
96 | transforms: {
|
97 | from: [
|
98 | {
|
99 | type: 'block',
|
100 | isMultiBlock: true,
|
101 | blocks: [ 'core/image' ],
|
102 | transform: ( attributes ) => {
|
103 |
|
104 | let { align } = attributes[ 0 ];
|
105 |
|
106 | align = every( attributes, [ 'align', align ] ) ? align : undefined;
|
107 |
|
108 | const validImages = filter( attributes, ( { id, url } ) => id && url );
|
109 |
|
110 | return createBlock( 'core/gallery', {
|
111 | images: validImages.map( ( { id, url, alt, caption } ) => ( { id, url, alt, caption } ) ),
|
112 | ids: validImages.map( ( { id } ) => id ),
|
113 | align,
|
114 | } );
|
115 | },
|
116 | },
|
117 | {
|
118 | type: 'shortcode',
|
119 | tag: 'gallery',
|
120 | attributes: {
|
121 | images: {
|
122 | type: 'array',
|
123 | shortcode: ( { named: { ids } } ) => {
|
124 | return parseShortcodeIds( ids ).map( ( id ) => ( {
|
125 | id,
|
126 | } ) );
|
127 | },
|
128 | },
|
129 | ids: {
|
130 | type: 'array',
|
131 | shortcode: ( { named: { ids } } ) => {
|
132 | return parseShortcodeIds( ids );
|
133 | },
|
134 | },
|
135 | columns: {
|
136 | type: 'number',
|
137 | shortcode: ( { named: { columns = '3' } } ) => {
|
138 | return parseInt( columns, 10 );
|
139 | },
|
140 | },
|
141 | linkTo: {
|
142 | type: 'string',
|
143 | shortcode: ( { named: { link = 'attachment' } } ) => {
|
144 | return link === 'file' ? 'media' : link;
|
145 | },
|
146 | },
|
147 | },
|
148 | },
|
149 | {
|
150 |
|
151 | type: 'files',
|
152 | isMatch( files ) {
|
153 | return files.length !== 1 && every( files, ( file ) => file.type.indexOf( 'image/' ) === 0 );
|
154 | },
|
155 | transform( files, onChange ) {
|
156 | const block = createBlock( 'core/gallery', {
|
157 | images: files.map( ( file ) => pickRelevantMediaFiles( {
|
158 | url: createBlobURL( file ),
|
159 | } ) ),
|
160 | } );
|
161 | mediaUpload( {
|
162 | filesList: files,
|
163 | onFileChange: ( images ) => {
|
164 | const imagesAttr = images.map(
|
165 | pickRelevantMediaFiles
|
166 | );
|
167 | onChange( block.clientId, {
|
168 | ids: map( imagesAttr, 'id' ),
|
169 | images: imagesAttr,
|
170 | } );
|
171 | },
|
172 | allowedTypes: [ 'image' ],
|
173 | } );
|
174 | return block;
|
175 | },
|
176 | },
|
177 | ],
|
178 | to: [
|
179 | {
|
180 | type: 'block',
|
181 | blocks: [ 'core/image' ],
|
182 | transform: ( { images, align } ) => {
|
183 | if ( images.length > 0 ) {
|
184 | return images.map( ( { id, url, alt, caption } ) => createBlock( 'core/image', { id, url, alt, caption, align } ) );
|
185 | }
|
186 | return createBlock( 'core/image', { align } );
|
187 | },
|
188 | },
|
189 | ],
|
190 | },
|
191 |
|
192 | edit,
|
193 |
|
194 | save( { attributes } ) {
|
195 | const { images, columns = defaultColumnsNumber( attributes ), imageCrop, linkTo } = attributes;
|
196 | return (
|
197 | <ul className={ `columns-${ columns } ${ imageCrop ? 'is-cropped' : '' }` } >
|
198 | { images.map( ( image ) => {
|
199 | let href;
|
200 |
|
201 | switch ( linkTo ) {
|
202 | case 'media':
|
203 | href = image.url;
|
204 | break;
|
205 | case 'attachment':
|
206 | href = image.link;
|
207 | break;
|
208 | }
|
209 |
|
210 | const img = <img src={ image.url } alt={ image.alt } data-id={ image.id } data-link={ image.link } className={ image.id ? `wp-image-${ image.id }` : null } />;
|
211 |
|
212 | return (
|
213 | <li key={ image.id || image.url } className="blocks-gallery-item">
|
214 | <figure>
|
215 | { href ? <a href={ href }>{ img }</a> : img }
|
216 | { image.caption && image.caption.length > 0 && (
|
217 | <RichText.Content tagName="figcaption" value={ image.caption } />
|
218 | ) }
|
219 | </figure>
|
220 | </li>
|
221 | );
|
222 | } ) }
|
223 | </ul>
|
224 | );
|
225 | },
|
226 |
|
227 | deprecated: [
|
228 | {
|
229 | attributes: blockAttributes,
|
230 | isEligible( { images, ids } ) {
|
231 | return images &&
|
232 | images.length > 0 &&
|
233 | (
|
234 | ( ! ids && images ) ||
|
235 | ( ids && images && ids.length !== images.length ) ||
|
236 | some( images, ( id, index ) => {
|
237 | if ( ! id && ids[ index ] !== null ) {
|
238 | return true;
|
239 | }
|
240 | return parseInt( id, 10 ) !== ids[ index ];
|
241 | } )
|
242 | );
|
243 | },
|
244 | migrate( attributes ) {
|
245 | return {
|
246 | ...attributes,
|
247 | ids: map( attributes.images, ( { id } ) => {
|
248 | if ( ! id ) {
|
249 | return null;
|
250 | }
|
251 | return parseInt( id, 10 );
|
252 | } ),
|
253 | };
|
254 | },
|
255 | save( { attributes } ) {
|
256 | const { images, columns = defaultColumnsNumber( attributes ), imageCrop, linkTo } = attributes;
|
257 | return (
|
258 | <ul className={ `columns-${ columns } ${ imageCrop ? 'is-cropped' : '' }` } >
|
259 | { images.map( ( image ) => {
|
260 | let href;
|
261 |
|
262 | switch ( linkTo ) {
|
263 | case 'media':
|
264 | href = image.url;
|
265 | break;
|
266 | case 'attachment':
|
267 | href = image.link;
|
268 | break;
|
269 | }
|
270 |
|
271 | const img = <img src={ image.url } alt={ image.alt } data-id={ image.id } data-link={ image.link } className={ image.id ? `wp-image-${ image.id }` : null } />;
|
272 |
|
273 | return (
|
274 | <li key={ image.id || image.url } className="blocks-gallery-item">
|
275 | <figure>
|
276 | { href ? <a href={ href }>{ img }</a> : img }
|
277 | { image.caption && image.caption.length > 0 && (
|
278 | <RichText.Content tagName="figcaption" value={ image.caption } />
|
279 | ) }
|
280 | </figure>
|
281 | </li>
|
282 | );
|
283 | } ) }
|
284 | </ul>
|
285 | );
|
286 | },
|
287 | },
|
288 | {
|
289 | attributes: blockAttributes,
|
290 | save( { attributes } ) {
|
291 | const { images, columns = defaultColumnsNumber( attributes ), imageCrop, linkTo } = attributes;
|
292 | return (
|
293 | <ul className={ `columns-${ columns } ${ imageCrop ? 'is-cropped' : '' }` } >
|
294 | { images.map( ( image ) => {
|
295 | let href;
|
296 |
|
297 | switch ( linkTo ) {
|
298 | case 'media':
|
299 | href = image.url;
|
300 | break;
|
301 | case 'attachment':
|
302 | href = image.link;
|
303 | break;
|
304 | }
|
305 |
|
306 | const img = <img src={ image.url } alt={ image.alt } data-id={ image.id } data-link={ image.link } />;
|
307 |
|
308 | return (
|
309 | <li key={ image.id || image.url } className="blocks-gallery-item">
|
310 | <figure>
|
311 | { href ? <a href={ href }>{ img }</a> : img }
|
312 | { image.caption && image.caption.length > 0 && (
|
313 | <RichText.Content tagName="figcaption" value={ image.caption } />
|
314 | ) }
|
315 | </figure>
|
316 | </li>
|
317 | );
|
318 | } ) }
|
319 | </ul>
|
320 | );
|
321 | },
|
322 | },
|
323 | {
|
324 | attributes: {
|
325 | ...blockAttributes,
|
326 | images: {
|
327 | ...blockAttributes.images,
|
328 | selector: 'div.wp-block-gallery figure.blocks-gallery-image img',
|
329 | },
|
330 | align: {
|
331 | type: 'string',
|
332 | default: 'none',
|
333 | },
|
334 | },
|
335 |
|
336 | save( { attributes } ) {
|
337 | const { images, columns = defaultColumnsNumber( attributes ), align, imageCrop, linkTo } = attributes;
|
338 | return (
|
339 | <div className={ `align${ align } columns-${ columns } ${ imageCrop ? 'is-cropped' : '' }` } >
|
340 | { images.map( ( image ) => {
|
341 | let href;
|
342 |
|
343 | switch ( linkTo ) {
|
344 | case 'media':
|
345 | href = image.url;
|
346 | break;
|
347 | case 'attachment':
|
348 | href = image.link;
|
349 | break;
|
350 | }
|
351 |
|
352 | const img = <img src={ image.url } alt={ image.alt } data-id={ image.id } />;
|
353 |
|
354 | return (
|
355 | <figure key={ image.id || image.url } className="blocks-gallery-image">
|
356 | { href ? <a href={ href }>{ img }</a> : img }
|
357 | </figure>
|
358 | );
|
359 | } ) }
|
360 | </div>
|
361 | );
|
362 | },
|
363 | },
|
364 | ],
|
365 | };
|