components
1 year ago
hooks
1 year ago
block.json
1 year ago
edit.js
1 year ago
editor.scss
1 year ago
image-utils.js
1 year ago
index.js
1 year ago
save.js
1 year ago
toolbar-appenders.js
1 year ago
transforms.js
1 year ago
edit.js
228 lines
| 1 | import { useBlockProps, InspectorControls } from '@wordpress/block-editor'; |
| 2 | import { useEffect, useState } from '@wordpress/element'; |
| 3 | import { compose } from '@wordpress/compose'; |
| 4 | import { isBlobURL, getBlobByURL, revokeBlobURL } from '@wordpress/blob'; |
| 5 | import { useSelect } from '@wordpress/data'; |
| 6 | |
| 7 | import { BlockStyles, withUniqueId } from '@edge22/block-styles'; |
| 8 | |
| 9 | import { useImageFunctions } from './hooks/useImageFunctions.js'; |
| 10 | import { Image } from './components/Image.jsx'; |
| 11 | import { withDynamicTag } from '../../hoc/withDynamicTag.js'; |
| 12 | import RootElement from '../../components/root-element/index.js'; |
| 13 | import { BlockSettings } from './components/BlockSettings'; |
| 14 | import { withStyles } from '@hoc/withStyles'; |
| 15 | import { BlockStylesBuilder, StylesOnboarder } from '@components/index'; |
| 16 | import { withHtmlAttributes } from '@hoc/withHtmlAttributes.js'; |
| 17 | import { getBlockClasses } from '@utils/getBlockClasses.js'; |
| 18 | |
| 19 | function EditBlock( props ) { |
| 20 | const { |
| 21 | attributes, |
| 22 | setAttributes, |
| 23 | isSelected, |
| 24 | name, |
| 25 | clientId, |
| 26 | onStyleChange, |
| 27 | editorHtmlAttributes, |
| 28 | htmlAttributes, |
| 29 | styles, |
| 30 | } = props; |
| 31 | |
| 32 | const { |
| 33 | tagName, |
| 34 | linkHtmlAttributes = {}, |
| 35 | } = attributes; |
| 36 | |
| 37 | const [ temporaryURL, setTemporaryURL ] = useState(); |
| 38 | const { isTemporaryImage, mediaUpload, onUploadError } = useImageFunctions(); |
| 39 | const classNames = getBlockClasses( |
| 40 | 'gb-media', |
| 41 | { |
| 42 | ...attributes, |
| 43 | styles, |
| 44 | } |
| 45 | ); |
| 46 | |
| 47 | useEffect( () => { |
| 48 | if ( ! tagName ) { |
| 49 | setAttributes( { tagName: 'img' } ); |
| 50 | } |
| 51 | }, [ tagName ] ); |
| 52 | |
| 53 | const { |
| 54 | isBlockMultiSelected, |
| 55 | } = useSelect( ( select ) => select( 'core/block-editor' ), [] ); |
| 56 | |
| 57 | const blockProps = useBlockProps(); |
| 58 | const shouldWrapBlock = isSelected || isBlockMultiSelected( clientId ) || ( 'img' === tagName && ! temporaryURL && ! htmlAttributes?.src ); |
| 59 | const elementAttributes = { |
| 60 | className: classNames.join( ' ' ).trim(), |
| 61 | 'data-block': clientId, |
| 62 | ...editorHtmlAttributes, |
| 63 | }; |
| 64 | const TagName = tagName || 'img'; |
| 65 | |
| 66 | function onSelectImage( image ) { |
| 67 | if ( ! image || ! image.url ) { |
| 68 | onResetImage(); |
| 69 | return; |
| 70 | } |
| 71 | |
| 72 | if ( isBlobURL( image.url ) ) { |
| 73 | setTemporaryURL( image.url ); |
| 74 | } |
| 75 | |
| 76 | setTemporaryURL(); |
| 77 | |
| 78 | if ( !! image ) { |
| 79 | const newAttributes = { |
| 80 | ...htmlAttributes, |
| 81 | src: image.url, |
| 82 | alt: image.alt, |
| 83 | title: image.title, |
| 84 | height: image.height, |
| 85 | width: image.width, |
| 86 | }; |
| 87 | |
| 88 | setAttributes( { |
| 89 | htmlAttributes: newAttributes, |
| 90 | mediaId: image.id ?? 0, |
| 91 | } ); |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | function onSelectURL( newURL ) { |
| 96 | if ( newURL === htmlAttributes.src ) { |
| 97 | return; |
| 98 | } |
| 99 | |
| 100 | const newAttributes = { |
| 101 | ...htmlAttributes, |
| 102 | src: newURL, |
| 103 | }; |
| 104 | |
| 105 | setAttributes( { htmlAttributes: newAttributes } ); |
| 106 | } |
| 107 | |
| 108 | function onResetImage() { |
| 109 | const newAttributes = { ...htmlAttributes }; |
| 110 | delete newAttributes.src; |
| 111 | delete newAttributes.alt; |
| 112 | delete newAttributes.title; |
| 113 | |
| 114 | setAttributes( { |
| 115 | htmlAttributes: newAttributes, |
| 116 | mediaId: 0, |
| 117 | } ); |
| 118 | } |
| 119 | |
| 120 | let isTemp = isTemporaryImage( htmlAttributes?.src ); |
| 121 | |
| 122 | useEffect( () => { |
| 123 | if ( ! isTemp ) { |
| 124 | return; |
| 125 | } |
| 126 | |
| 127 | const file = getBlobByURL( htmlAttributes?.src ); |
| 128 | |
| 129 | if ( file ) { |
| 130 | mediaUpload( { |
| 131 | filesList: [ file ], |
| 132 | onFileChange: ( [ img ] ) => { |
| 133 | onSelectImage( img ); |
| 134 | }, |
| 135 | allowedTypes: [ 'image' ], |
| 136 | onError: ( message ) => { |
| 137 | isTemp = false; |
| 138 | onUploadError( message ); |
| 139 | }, |
| 140 | } ); |
| 141 | } |
| 142 | }, [] ); |
| 143 | |
| 144 | // If an image is temporary, revoke the Blob url when it is uploaded (and is |
| 145 | // no longer temporary). |
| 146 | useEffect( () => { |
| 147 | if ( isTemp ) { |
| 148 | setTemporaryURL( htmlAttributes?.src ); |
| 149 | return; |
| 150 | } |
| 151 | revokeBlobURL( temporaryURL ); |
| 152 | }, [ isTemp, htmlAttributes?.src ] ); |
| 153 | |
| 154 | function elementRender() { |
| 155 | return ( |
| 156 | <> |
| 157 | { 'img' === tagName ? ( |
| 158 | <Image |
| 159 | { ...props } |
| 160 | elementAttributes={ elementAttributes } |
| 161 | temporaryURL={ temporaryURL } |
| 162 | onSelectImage={ onSelectImage } |
| 163 | onSelectURL={ onSelectURL } |
| 164 | onResetImage={ onResetImage } |
| 165 | onUploadError={ onUploadError } |
| 166 | linkHtmlAttributes={ linkHtmlAttributes } |
| 167 | /> |
| 168 | ) : ( |
| 169 | <TagName { ...elementAttributes } /> |
| 170 | ) } |
| 171 | </> |
| 172 | ); |
| 173 | } |
| 174 | |
| 175 | return ( |
| 176 | <> |
| 177 | <InspectorControls> |
| 178 | <StylesOnboarder /> |
| 179 | |
| 180 | <BlockStyles |
| 181 | settingsTab={ ( |
| 182 | <BlockSettings |
| 183 | { ...props } |
| 184 | onSelectImage={ onSelectImage } |
| 185 | /> |
| 186 | ) } |
| 187 | stylesTab={ ( |
| 188 | <BlockStylesBuilder |
| 189 | attributes={ attributes } |
| 190 | setAttributes={ setAttributes } |
| 191 | shortcuts={ {} } |
| 192 | onStyleChange={ onStyleChange } |
| 193 | name={ name } |
| 194 | /> |
| 195 | ) } |
| 196 | /> |
| 197 | </InspectorControls> |
| 198 | |
| 199 | <RootElement |
| 200 | name={ name } |
| 201 | clientId={ clientId } |
| 202 | > |
| 203 | <div |
| 204 | { ...blockProps } |
| 205 | data-block-wrapper |
| 206 | style={ { |
| 207 | display: ! shouldWrapBlock ? 'none' : undefined, |
| 208 | } } |
| 209 | > |
| 210 | { elementRender() } |
| 211 | </div> |
| 212 | <div style={ { display: shouldWrapBlock ? 'none' : 'contents' } }> |
| 213 | { elementRender() } |
| 214 | </div> |
| 215 | </RootElement> |
| 216 | </> |
| 217 | ); |
| 218 | } |
| 219 | |
| 220 | const Edit = compose( |
| 221 | withHtmlAttributes, |
| 222 | withStyles, |
| 223 | withDynamicTag, |
| 224 | withUniqueId |
| 225 | )( EditBlock ); |
| 226 | |
| 227 | export { Edit }; |
| 228 |