Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Added InnerBlock Support for Download Button & Add Support for download attribute #68510

Open
wants to merge 3 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Prompt visitors to take action with a button-style link. ([Source](https://githu
- **Category:** design
- **Parent:** core/buttons
- **Supports:** anchor, color (background, gradients, text), interactivity (clientNavigation), shadow (), spacing (padding), splitting, typography (fontSize, lineHeight), ~~alignWide~~, ~~align~~, ~~reusable~~
- **Attributes:** backgroundColor, gradient, linkTarget, placeholder, rel, tagName, text, textAlign, textColor, title, type, url, width
- **Attributes:** backgroundColor, download, gradient, linkTarget, placeholder, rel, tagName, text, textAlign, textColor, title, type, url, width

## Buttons

Expand Down Expand Up @@ -273,7 +273,7 @@ Add a link to a downloadable file. ([Source](https://github.com/WordPress/gutenb
- **Name:** core/file
- **Category:** media
- **Supports:** align, anchor, color (background, gradients, link, ~~text~~), interactivity, spacing (margin, padding)
- **Attributes:** blob, displayPreview, downloadButtonText, fileId, fileName, href, id, previewHeight, showDownloadButton, textLinkHref, textLinkTarget
- **Attributes:** blob, displayPreview, fileId, fileName, href, id, previewHeight, showDownloadButton, textLinkHref, textLinkTarget

## Footnotes

Expand Down
7 changes: 7 additions & 0 deletions packages/block-library/src/button/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@
"attribute": "rel",
"role": "content"
},
"download": {
"type": "boolean",
"source": "attribute",
"selector": "a",
"attribute": "download",
"role": "content"
},
"placeholder": {
"type": "string"
},
Expand Down
6 changes: 6 additions & 0 deletions packages/block-library/src/button/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ const LINK_SETTINGS = [
id: 'nofollow',
title: __( 'Mark as nofollow' ),
},
{
id: 'download',
title: __( 'Download file' ),
},
];

function useEnter( props ) {
Expand Down Expand Up @@ -380,13 +384,15 @@ function ButtonEdit( props ) {
url: newURL,
opensInNewTab: newOpensInNewTab,
nofollow: newNofollow,
download: newDownload,
} ) =>
setAttributes(
getUpdatedLinkAttributes( {
rel,
url: newURL,
opensInNewTab: newOpensInNewTab,
nofollow: newNofollow,
download: newDownload,
} )
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ import { prependHTTP } from '@wordpress/url';
* @param {string} attributes.url The current link url.
* @param {boolean} attributes.opensInNewTab Whether the link should open in a new window.
* @param {boolean} attributes.nofollow Whether the link should be marked as nofollow.
* @param {boolean} attributes.download Whether the link should allow download.
*/
export function getUpdatedLinkAttributes( {
rel = '',
url = '',
opensInNewTab,
nofollow,
download = false,
} ) {
let newLinkTarget;
// Since `rel` is editable attribute, we need to check for existing values and proceed accordingly.
Expand All @@ -46,9 +48,33 @@ export function getUpdatedLinkAttributes( {
updatedRel = updatedRel?.replace( relRegex, '' ).trim();
}

const allowDownload = url && isSameOrigin( url ) ? download : undefined;

return {
url: prependHTTP( url ),
linkTarget: newLinkTarget,
rel: updatedRel || undefined,
download: allowDownload,
};
}

/**
* Checks if the URL is same origin.
* Allow relative URLs.
*
* @param {string} urlString The URL to check.
* @return {boolean} Whether the URL is same origin.
*/
function isSameOrigin( urlString ) {
// Allow relative URLs
if ( urlString.startsWith( '/' ) ) {
return true;
}

try {
const url = new URL( urlString, window.location.origin );
return url.origin === window.location.origin;
} catch {
return false;
}
}
2 changes: 2 additions & 0 deletions packages/block-library/src/button/save.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default function save( { attributes, className } ) {
title,
url,
width,
download,
} = attributes;

const TagName = tagName || 'a';
Expand Down Expand Up @@ -83,6 +84,7 @@ export default function save( { attributes, className } ) {
value={ text }
target={ isButtonTag ? null : linkTarget }
rel={ isButtonTag ? null : rel }
download={ isButtonTag ? null : download }
/>
</div>
);
Expand Down
6 changes: 0 additions & 6 deletions packages/block-library/src/file/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,6 @@
"type": "boolean",
"default": true
},
"downloadButtonText": {
"type": "rich-text",
"source": "rich-text",
"selector": "a[download]",
"role": "content"
},
"displayPreview": {
"type": "boolean"
},
Expand Down
78 changes: 35 additions & 43 deletions packages/block-library/src/file/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ import {
RichText,
useBlockProps,
store as blockEditorStore,
__experimentalGetElementClassName,
useInnerBlocksProps,
} from '@wordpress/block-editor';
import { useEffect, useState } from '@wordpress/element';
import { useState } from '@wordpress/element';
import { useCopyToClipboard } from '@wordpress/compose';
import { __, _x } from '@wordpress/i18n';
import { __ } from '@wordpress/i18n';
import { file as icon } from '@wordpress/icons';
import { store as coreStore } from '@wordpress/core-data';
import { store as noticesStore } from '@wordpress/notices';
Expand Down Expand Up @@ -69,7 +69,6 @@ function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {
textLinkHref,
textLinkTarget,
showDownloadButton,
downloadButtonText,
displayPreview,
previewHeight,
} = attributes;
Expand All @@ -85,27 +84,14 @@ function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {
);

const { createErrorNotice } = useDispatch( noticesStore );
const { toggleSelection, __unstableMarkNextChangeAsNotPersistent } =
useDispatch( blockEditorStore );
const { toggleSelection } = useDispatch( blockEditorStore );

useUploadMediaFromBlobURL( {
url: temporaryURL,
onChange: onSelectFile,
onError: onUploadError,
} );

// Note: Handle setting a default value for `downloadButtonText` via HTML API
// when it supports replacing text content for HTML tags.
useEffect( () => {
if ( RichText.isEmpty( downloadButtonText ) ) {
__unstableMarkNextChangeAsNotPersistent();
setAttributes( {
downloadButtonText: _x( 'Download', 'button label' ),
} );
}
// This effect should only run on mount.
}, [] );

function onSelectFile( newMedia ) {
if ( ! newMedia || ! newMedia.url ) {
// Reset attributes.
Expand Down Expand Up @@ -199,6 +185,36 @@ function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {

const displayPreviewInEditor = browserSupportsPdfs() && displayPreview;

const innerBlocksProps = useInnerBlocksProps(
{ className: 'wp-block-file__button-wrapper' },
{
allowedBlocks: [ 'core/buttons' ],
template: [
[
'core/buttons',
{},
[
[
'core/button',
{
text: __( 'Download' ),
lock: {
remove: true,
move: true,
},
url: href || temporaryURL,
download: true,
ariaLabel: __( 'Download button text' ),
},
],
],
],
],
templateLock: 'all',
renderAppender: false,
}
);

if ( ! href && ! temporaryURL ) {
return (
<div { ...blockProps }>
Expand Down Expand Up @@ -301,31 +317,7 @@ function FileEdit( { attributes, isSelected, setAttributes, clientId } ) {
}
href={ textLinkHref }
/>
{ showDownloadButton && (
<div className="wp-block-file__button-richtext-wrapper">
{ /* Using RichText here instead of PlainText so that it can be styled like a button. */ }
<RichText
identifier="downloadButtonText"
tagName="div" // Must be block-level or else cursor disappears.
aria-label={ __( 'Download button text' ) }
className={ clsx(
'wp-block-file__button',
__experimentalGetElementClassName(
'button'
)
) }
value={ downloadButtonText }
withoutInteractiveFormatting
placeholder={ __( 'Add text…' ) }
onChange={ ( text ) =>
setAttributes( {
downloadButtonText:
removeAnchorTag( text ),
} )
}
/>
</div>
) }
{ showDownloadButton && <div { ...innerBlocksProps } /> }
</div>
</div>
</>
Expand Down
11 changes: 5 additions & 6 deletions packages/block-library/src/file/editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@
}

.wp-block-file__content-wrapper {
flex-grow: 1;
display: flex;
align-items: center;
gap: 1em;
flex-wrap: wrap;
width: 100%;
}

a {
Expand All @@ -43,9 +47,4 @@
display: inline-block;
}
}

.wp-block-file__button-richtext-wrapper {
display: inline-block;
margin-left: 0.75em;
}
}
33 changes: 12 additions & 21 deletions packages/block-library/src/file/save.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
/**
* External dependencies
*/
import clsx from 'clsx';

/**
* WordPress dependencies
*/
import {
RichText,
useBlockProps,
__experimentalGetElementClassName,
useInnerBlocksProps,
} from '@wordpress/block-editor';

export default function save( { attributes } ) {
Expand All @@ -20,7 +15,6 @@ export default function save( { attributes } ) {
textLinkHref,
textLinkTarget,
showDownloadButton,
downloadButtonText,
displayPreview,
previewHeight,
} = attributes;
Expand All @@ -37,9 +31,18 @@ export default function save( { attributes } ) {
// actually rendered.
const describedById = hasFilename ? fileId : undefined;

const blockProps = useBlockProps.save( {
className: 'wp-block-file',
} );

// Use the `useInnerBlocksProps` hook to get the props for the inner blocks
const innerBlocksProps = useInnerBlocksProps.save( {
className: 'wp-block-file__button-wrapper',
} );

return (
href && (
<div { ...useBlockProps.save() }>
<div { ...blockProps }>
{ displayPreview && (
<>
<object
Expand All @@ -66,19 +69,7 @@ export default function save( { attributes } ) {
<RichText.Content value={ fileName } />
</a>
) }
{ showDownloadButton && (
<a
href={ href }
className={ clsx(
'wp-block-file__button',
__experimentalGetElementClassName( 'button' )
) }
download
aria-describedby={ describedById }
>
<RichText.Content value={ downloadButtonText } />
</a>
) }
{ showDownloadButton && <div { ...innerBlocksProps } /> }
</div>
)
);
Expand Down
Loading
Loading