-
Notifications
You must be signed in to change notification settings - Fork 4.3k
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
Implement File block #6805
Implement File block #6805
Conversation
Tried to check this out and run it. VERY cool work! Very very nice, definitely getting there. A few niggles: Can we make it so you can drag and drop a PDF file directly into the canvas, in addition to on the file block placeholder? It would be nice if the Download button text were editable. Perhaps even that you could toggle off the download button entirely in the sidebar. If you remove the actual link from the button inside the editor, so you can't download from inside the editor but only on the published front-end, then you could make the button clickable to edit, just like the normal Button block. Given that you can edit the text of the link, right now the "Edit" button taking you back to the placeholder feels a little bit jarring. Could you make it so instead of having the layout alignment buttons and an edit button, it has instead text-block-like editing tools? Instead of: You'd have: This would essentially be like a text field with a button. You could write your own text, link, unlink, bold, italic, etc. You'd never be able to go back to the placeholder block from the final state, but that's fine too, and the button would always hold the link. What do you think? I notice by the way that if you edit the link, you're typing in reverse :) — but I'll bet that's what you refer to in the remaining bullet.
We probably don't need these, but nice idea otherwise! Very cool work, thanks for working on this, and keep up he good work! |
Thanks for the review, @jasmussen!
If so, it is already supposed to be working. You might be seeing a bug. Could you give me some more details so I can reproduce it?
Sure! We could do that.
Hmm, I thought about this too. At one point I even considered a hybrid approach:
My main concern is that we’d confuse the user’s mental model of where the “source of truth” for the file link is. Since choosing a file from the placeholder sets both links, you can reasonably assume that both links will change if you choose another file from the same interface: But when you introduce a second way to change the link, it’s harder to tell what’s going to happen. If only the text link were to change, it would become hard to tell that the text link and button link are out of sync. On the other hand, if both links were to change, it would break the expectation of the standard rich text UI: Is this a tradeoff we are willing to take? Let me know what you think 🙂 |
Those are the wide and full-width alignment options, which do not show unless your theme declares support for them, since those kinds of alignments extend out of the standard content width and may not look right depending on the theme. Since Gutenberg is so new, there are very few themes that have declared support for those alignment types, so most of the time you will only see those options if you use a custom child theme which has declared support for them. |
@SuperGeniusZeb Oh I see, that makes sense now. Thank you! |
Placeholder text state was not properly updating when uploading a file from the media placeholder.
Very nice work! Here's a GIF of it: Experience wise, this seems to behave as we've discussed, and given the paradigms Gutenberg works with, this seems like it solves the task at hand:
For the scope of this task, 👍 👍, I think this is cool! Nice work. Did you include/merge the work from master that unifies the placeholder block? At some point in the future, as a separate project to this, I imagine that we'll want to take a look at the media library in WordPress in general. In doing so, there will likely also be an opportunity to look at how the placeholder block can work. For example it would be nice if we could show part of the media library itself inside the placeholder block, and allow you to simply drag into it there, and then insert as file block or insert as plaintext link. But that's something to consider for the future. |
@jasmussen Thank you for all your guidance, and the cool gif! There are so many possibilities with the Gutenberg framework, and I'm excited to see how the UX will evolve. Hope I'll have a chance to contribute more.
Yes. The code is a lot cleaner thanks to that. And there's another modification in the works (#6957), so if that gets merged in first I'll get to delete a few more lines 🙂 |
// the document.activeElement at the moment when the copy event fires. | ||
// This causes documentHasSelection() in the copy-handler component to | ||
// mistakenly override the ClipboardButton, and copy a serialized string | ||
// of the current block instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the detailed comment, explaining why do we have the workaround.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One problem in Safari, though, is that the while block (<!-- wp:file {"href":…
) ends up in the clipboard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, it looks like this workaround hadn't fixed the Safari bug completely. I did some testing and narrowed down the repro condition a bit. My workaround seems to be effective for pre-existing posts (i.e. posts that were already saved when the page loaded), but not for new posts. Not sure what's going on, but that's a start... I'll have to look into it further.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in #7106
getBlobByURL( href ) | ||
.then( ( file ) => { | ||
editorMediaUpload( { | ||
allowedType: '*', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to make sure I understand correctly, once #6968 gets in we will feed the list if types here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that allowedType
is being used for limiting the files to a suggested file type, similar to the accept
attribute of an <input type="file">
. The naming is very confusing right now. I want to rename that to accept
(and maybe enhance it to take comma-separated and file extension arguments like the actual <input accept>
) in a separate PR once this and #6968 are merged in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From #5462:
WordPress also supports a number of filetypes that aren't media, such as pdf, doc, and others. See full list here: https://codex.wordpress.org/Uploading_Files
I don't think that editorMediaUpload
in the current shape is what we really want to use in here, because non-media files can be uploaded, too. It seems like we need to refactor the existing method or add a more generic one which editorMediaUpload
uses behind the scenes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I was under the impression that the "media" in editorMediaUpload
and mediaUpload
is being used in the broader sense of the word, and not to mean "images, audio, and video". This is in line with how WordPress uses the term — every kind of uploadable file, including pdf and other documents, are uploaded to the "Media Library", and are retrieved via the media
endpoint.
Even /edit-post/hooks/blocks/media-upload, which includes specific logic for when gallery == true, seems generic enough for any kind of file. Is there a reason we want to keep editorMediaUpload
specifically for image/audio/video files?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I posted a separate issue for the allowedType
problem: #7155
} | ||
} | ||
|
||
isBlobURL( url = '' ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to move this one to utils
, like the other blob functions? At which point would you split out utils/blob
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think so. But in a separate PR, because I think I saw a couple of other places in the codebase where we’re doing blob url detection, and I’d want to change them all at once.
<a | ||
href={ textLinkHref } | ||
target={ openInNewWindow } | ||
rel={ openInNewWindow ? 'noreferrer noopener' : false } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the noreferrer
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it’s because noopener
doesn’t work in IE/Edge. (see also: #6186)
core-blocks/file/edit.js
Outdated
|
||
// edit component has its own attributes in the state so it can be edited | ||
// without setting the actual values outside of the edit UI | ||
this.state = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure I follow the reason we keep the attributes in the state, too. What do we gain?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I've cleaned them out.
core-blocks/file/edit.js
Outdated
|
||
if ( id !== undefined ) { | ||
// Get Attachment Page URL | ||
wp.apiRequest( { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason we’re not using withAPIData here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't realize we had that! Cool. I put that in place, however it turns out that the snapshot test helper for our components (blockEditRender()
) isn't equipped to inject context
in order for it to work. I've made a patch for it and I'll propose it in a separate PR, but not sure if my implementation is good. Anyway, I'm going to remove the snapshot test for this temporarily.
core-blocks/file/edit.js
Outdated
} ) | ||
.then( | ||
( result ) => { | ||
this.setState( { attachmentPage: result.link } ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would the setState
work correctly if the component hasn't been rendered yet?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Should've been in componentDidMount()
.
|
||
componentDidUpdate( prevProps ) { | ||
// Reset copy confirmation state when block is deselected | ||
if ( prevProps.isSelected && ! this.props.isSelected ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This worked great for me as a user.
|
||
componentDidUpdate( prevProps ) { | ||
if ( prevProps.text !== this.props.text ) { | ||
this.setState( { showPlaceholder: ! this.props.text } ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are the trade-offs of using state here vs. just using the text
prop for rendering logic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since I'm resorting to use a content-editable here, this is not a "controlled" component and therefore the text
prop isn't updated on each keystroke.
Requires a modification in the `blockEditRender()` test helper to inject context, or else the withAPIData HOC won’t work.
…file-block # Conflicts: # utils/mediaupload.js
core-blocks/file/edit.js
Outdated
this.setState( { | ||
attachmentPage: media.link, | ||
} ); | ||
}, this.props.media.get /* refetch attachment page url */ ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does setAttributes
accept a second argument? When is this.props.media.get
called?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Totally assumed setAttributes
took the same arguments as setState
! I meant it as a callback. Thank you.
core-blocks/file/edit.js
Outdated
|
||
export default compose( [ | ||
withAPIData( ( props ) => ( { | ||
media: `/wp/v2/media/${ props.attributes.id }`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export default compose( [
withSelect( ( select, props ) => {
const { getMedia } = select( 'core' );
return {
image: getMedia( props.attributes.id ), // not sure if getMedia handles undefined values
};
} ),
withNotices,
] )( FileEdit );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, I wasn't aware of this. I'll look into it.
@@ -33,7 +33,9 @@ export function mediaUpload( { | |||
filesSet[ idx ] = value; | |||
onFileChange( compact( filesSet ) ); | |||
}; | |||
const isAllowedType = ( fileType ) => startsWith( fileType, `${ allowedType }/` ); | |||
const isAllowedType = ( fileType ) => { | |||
return ( allowedType === '*' ) || startsWith( fileType, `${ allowedType }/` ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it rather list all allowed file types by allowing the array format?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think it should accept arrays, as well as have a more predictable syntax. More on that here: #7155
I opted for a wildcard here as a stop-gap measure, or else we'd have something like ['audio', 'application', 'video', 'text', 'image', 'font']
which I think is more error-prone for consumers.
By the way, here are some of the RichText issues that caused me to resort to a Now that I've sorted through the repro conditions and workarounds for them, I feel like #7591 is the only "blocker" for using a RichText here. If that is addressed, I think we could safely replace the contenteditable. |
Closes #5462
Description
Implements a File block with the following features:
both Media Library files and external URLsonly Media Library files(?) Background Color and Text Color options in sidebarHow has this been tested?
Try the features above.
Screenshots
Things I don't plan on including in this PR (but should be done eventually)
Integrate error messaging using Fix max upload size error message #4203done, thanks to Try unifying all the media blocks placeholder under a unique component #6820Add allowed mime type checking to Fix max upload size error message #4203submitted separately as Check allowed mime types before uploading media #6968Refactor the misplaced CSS in core-blocks/image/editor.scssdone, thanks to Try unifying all the media blocks placeholder under a unique component #6820Copy URL button may not work correctly in Safarisubmitted separately as Make ClipboardButton inside a block work correctly in Safari #7106