UNPKG

@wordpress/block-editor

Version:
349 lines (307 loc) 10.6 kB
import { createElement, Fragment } from "@wordpress/element"; /** * External dependencies */ import { noop } from 'lodash'; import classnames from 'classnames'; /** * WordPress dependencies */ import { Button, FormFileUpload, Placeholder, DropZone, withFilters } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { useState, useEffect } from '@wordpress/element'; import { useSelect } from '@wordpress/data'; import deprecated from '@wordpress/deprecated'; import { keyboardReturn } from '@wordpress/icons'; /** * Internal dependencies */ import MediaUpload from '../media-upload'; import MediaUploadCheck from '../media-upload/check'; import URLPopover from '../url-popover'; import { store as blockEditorStore } from '../../store'; const InsertFromURLPopover = ({ src, onChange, onSubmit, onClose }) => createElement(URLPopover, { onClose: onClose }, createElement("form", { className: "block-editor-media-placeholder__url-input-form", onSubmit: onSubmit }, createElement("input", { className: "block-editor-media-placeholder__url-input-field", type: "url", "aria-label": __('URL'), placeholder: __('Paste or type URL'), onChange: onChange, value: src }), createElement(Button, { className: "block-editor-media-placeholder__url-input-submit-button", icon: keyboardReturn, label: __('Apply'), type: "submit" }))); export function MediaPlaceholder({ value = {}, allowedTypes, className, icon, labels = {}, mediaPreview, notices, isAppender, accept, addToGallery, multiple = false, dropZoneUIOnly, disableDropZone, disableMediaButtons, onError, onSelect, onCancel, onSelectURL, onDoubleClick, onFilesPreUpload = noop, onHTMLDrop = noop, children }) { const mediaUpload = useSelect(select => { const { getSettings } = select(blockEditorStore); return getSettings().mediaUpload; }, []); const [src, setSrc] = useState(''); const [isURLInputVisible, setIsURLInputVisible] = useState(false); useEffect(() => { var _value$src; setSrc((_value$src = value === null || value === void 0 ? void 0 : value.src) !== null && _value$src !== void 0 ? _value$src : ''); }, [value === null || value === void 0 ? void 0 : value.src]); const onlyAllowsImages = () => { if (!allowedTypes || allowedTypes.length === 0) { return false; } return allowedTypes.every(allowedType => allowedType === 'image' || allowedType.startsWith('image/')); }; const onChangeSrc = event => { setSrc(event.target.value); }; const openURLInput = () => { setIsURLInputVisible(true); }; const closeURLInput = () => { setIsURLInputVisible(false); }; const onSubmitSrc = event => { event.preventDefault(); if (src && onSelectURL) { onSelectURL(src); closeURLInput(); } }; const onFilesUpload = files => { onFilesPreUpload(files); let setMedia; if (multiple) { if (addToGallery) { // Since the setMedia function runs multiple times per upload group // and is passed newMedia containing every item in its group each time, we must // filter out whatever this upload group had previously returned to the // gallery before adding and returning the image array with replacement newMedia // values. // Define an array to store urls from newMedia between subsequent function calls. let lastMediaPassed = []; setMedia = newMedia => { // Remove any images this upload group is responsible for (lastMediaPassed). // Their replacements are contained in newMedia. const filteredMedia = (value !== null && value !== void 0 ? value : []).filter(item => { // If Item has id, only remove it if lastMediaPassed has an item with that id. if (item.id) { return !lastMediaPassed.some( // Be sure to convert to number for comparison. ({ id }) => Number(id) === Number(item.id)); } // Compare transient images via .includes since gallery may append extra info onto the url. return !lastMediaPassed.some(({ urlSlug }) => item.url.includes(urlSlug)); }); // Return the filtered media array along with newMedia. onSelect(filteredMedia.concat(newMedia)); // Reset lastMediaPassed and set it with ids and urls from newMedia. lastMediaPassed = newMedia.map(media => { // Add everything up to '.fileType' to compare via .includes. const cutOffIndex = media.url.lastIndexOf('.'); const urlSlug = media.url.slice(0, cutOffIndex); return { id: media.id, urlSlug }; }); }; } else { setMedia = onSelect; } } else { setMedia = ([media]) => onSelect(media); } mediaUpload({ allowedTypes, filesList: files, onFileChange: setMedia, onError }); }; const onUpload = event => { onFilesUpload(event.target.files); }; const renderPlaceholder = (content, onClick) => { let { instructions, title } = labels; if (!mediaUpload && !onSelectURL) { instructions = __('To edit this block, you need permission to upload media.'); } if (instructions === undefined || title === undefined) { const typesAllowed = allowedTypes !== null && allowedTypes !== void 0 ? allowedTypes : []; const [firstAllowedType] = typesAllowed; const isOneType = 1 === typesAllowed.length; const isAudio = isOneType && 'audio' === firstAllowedType; const isImage = isOneType && 'image' === firstAllowedType; const isVideo = isOneType && 'video' === firstAllowedType; if (instructions === undefined && mediaUpload) { instructions = __('Upload a media file or pick one from your media library.'); if (isAudio) { instructions = __('Upload an audio file, pick one from your media library, or add one with a URL.'); } else if (isImage) { instructions = __('Upload an image file, pick one from your media library, or add one with a URL.'); } else if (isVideo) { instructions = __('Upload a video file, pick one from your media library, or add one with a URL.'); } } if (title === undefined) { title = __('Media'); if (isAudio) { title = __('Audio'); } else if (isImage) { title = __('Image'); } else if (isVideo) { title = __('Video'); } } } const placeholderClassName = classnames('block-editor-media-placeholder', className, { 'is-appender': isAppender }); return createElement(Placeholder, { icon: icon, label: title, instructions: instructions, className: placeholderClassName, notices: notices, onClick: onClick, onDoubleClick: onDoubleClick, preview: mediaPreview }, content, children); }; const renderDropZone = () => { if (disableDropZone) { return null; } return createElement(DropZone, { onFilesDrop: onFilesUpload, onHTMLDrop: onHTMLDrop }); }; const renderCancelLink = () => { return onCancel && createElement(Button, { className: "block-editor-media-placeholder__cancel-button", title: __('Cancel'), isLink: true, onClick: onCancel }, __('Cancel')); }; const renderUrlSelectionUI = () => { return onSelectURL && createElement("div", { className: "block-editor-media-placeholder__url-input-container" }, createElement(Button, { className: "block-editor-media-placeholder__button", onClick: openURLInput, isPressed: isURLInputVisible, isTertiary: true }, __('Insert from URL')), isURLInputVisible && createElement(InsertFromURLPopover, { src: src, onChange: onChangeSrc, onSubmit: onSubmitSrc, onClose: closeURLInput })); }; const renderMediaUploadChecked = () => { const mediaLibraryButton = createElement(MediaUpload, { addToGallery: addToGallery, gallery: multiple && onlyAllowsImages(), multiple: multiple, onSelect: onSelect, allowedTypes: allowedTypes, value: Array.isArray(value) ? value.map(({ id }) => id) : value.id, render: ({ open }) => { return createElement(Button, { isTertiary: true, onClick: event => { event.stopPropagation(); open(); } }, __('Media Library')); } }); if (mediaUpload && isAppender) { return createElement(Fragment, null, renderDropZone(), createElement(FormFileUpload, { onChange: onUpload, accept: accept, multiple: multiple, render: ({ openFileDialog }) => { const content = createElement(Fragment, null, createElement(Button, { isPrimary: true, className: classnames('block-editor-media-placeholder__button', 'block-editor-media-placeholder__upload-button') }, __('Upload')), mediaLibraryButton, renderUrlSelectionUI(), renderCancelLink()); return renderPlaceholder(content, openFileDialog); } })); } if (mediaUpload) { const content = createElement(Fragment, null, renderDropZone(), createElement(FormFileUpload, { isPrimary: true, className: classnames('block-editor-media-placeholder__button', 'block-editor-media-placeholder__upload-button'), onChange: onUpload, accept: accept, multiple: multiple }, __('Upload')), mediaLibraryButton, renderUrlSelectionUI(), renderCancelLink()); return renderPlaceholder(content); } return renderPlaceholder(mediaLibraryButton); }; if (dropZoneUIOnly || disableMediaButtons) { if (dropZoneUIOnly) { deprecated('wp.blockEditor.MediaPlaceholder dropZoneUIOnly prop', { since: '5.4', alternative: 'disableMediaButtons' }); } return createElement(MediaUploadCheck, null, renderDropZone()); } return createElement(MediaUploadCheck, { fallback: renderPlaceholder(renderUrlSelectionUI()) }, renderMediaUploadChecked()); } /** * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/media-placeholder/README.md */ export default withFilters('editor.MediaPlaceholder')(MediaPlaceholder); //# sourceMappingURL=index.js.map