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

File Block: Add support for embedding PDFs #24233

Closed
wants to merge 14 commits into from
Closed

File Block: Add support for embedding PDFs #24233

wants to merge 14 commits into from

Conversation

pento
Copy link
Member

@pento pento commented Jul 28, 2020

Description

Fixes #19077.

This PR adds an option to the File block, when a PDF file is inserted, to show an embedded version of the PDF.

PDFs are a bit of a special case amongst files: they're the only document file type with native embed support in most major browsers (mobile devices excepted).

How has this been tested?

  • Insert a file block and select a PDF from the media library.
  • Drag/drop a PDF to upload it.
  • Switch from a PDF, to a different file type, and back again.
  • Tested in different browsers: Chrome, Firefox, Safari, Edge, IE11.
  • Tested on different OSes: MacOS, Windows 10, Android, iOS on iPhone, iOS on iPad.
  • Tested on IE11 with and without Acrobat Reader installed.

Screenshots

Types of changes

New feature.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PRx

@pento pento added [Block] File Affects the File Block [Type] Feature New feature to highlight in changelogs. labels Jul 28, 2020
@pento pento self-assigned this Jul 28, 2020
@github-actions
Copy link

github-actions bot commented Jul 28, 2020

Size Change: +776 B (0%)

Total Size: 1.16 MB

Filename Size Change
build/block-library/editor-rtl.css 7.62 kB +31 B (0%)
build/block-library/editor.css 7.62 kB +31 B (0%)
build/block-library/index.js 133 kB +706 B (0%)
build/block-library/style-rtl.css 7.77 kB +4 B (0%)
build/block-library/style.css 7.78 kB +4 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.14 kB 0 B
build/annotations/index.js 3.67 kB 0 B
build/api-fetch/index.js 3.44 kB 0 B
build/autop/index.js 2.82 kB 0 B
build/blob/index.js 620 B 0 B
build/block-directory/index.js 7.97 kB 0 B
build/block-directory/style-rtl.css 953 B 0 B
build/block-directory/style.css 952 B 0 B
build/block-editor/index.js 125 kB 0 B
build/block-editor/style-rtl.css 10.6 kB 0 B
build/block-editor/style.css 10.6 kB 0 B
build/block-library/blocks/file.js 859 B 0 B
build/block-library/theme-rtl.css 729 B 0 B
build/block-library/theme.css 730 B 0 B
build/block-serialization-default-parser/index.js 1.88 kB 0 B
build/block-serialization-spec-parser/index.js 3.1 kB 0 B
build/blocks/index.js 48.4 kB 0 B
build/components/index.js 200 kB 0 B
build/components/style-rtl.css 15.7 kB 0 B
build/components/style.css 15.7 kB 0 B
build/compose/index.js 9.68 kB 0 B
build/core-data/index.js 11.8 kB 0 B
build/data-controls/index.js 1.29 kB 0 B
build/data/index.js 8.45 kB 0 B
build/date/index.js 5.38 kB 0 B
build/deprecated/index.js 772 B 0 B
build/dom-ready/index.js 568 B 0 B
build/dom/index.js 3.23 kB 0 B
build/edit-navigation/index.js 10.9 kB 0 B
build/edit-navigation/style-rtl.css 1.08 kB 0 B
build/edit-navigation/style.css 1.08 kB 0 B
build/edit-post/index.js 304 kB 0 B
build/edit-post/style-rtl.css 5.62 kB 0 B
build/edit-post/style.css 5.61 kB 0 B
build/edit-site/index.js 17 kB 0 B
build/edit-site/style-rtl.css 3.06 kB 0 B
build/edit-site/style.css 3.06 kB 0 B
build/edit-widgets/index.js 9.38 kB 0 B
build/edit-widgets/style-rtl.css 2.45 kB 0 B
build/edit-widgets/style.css 2.45 kB 0 B
build/editor/editor-styles-rtl.css 537 B 0 B
build/editor/editor-styles.css 539 B 0 B
build/editor/index.js 45.3 kB 0 B
build/editor/style-rtl.css 3.8 kB 0 B
build/editor/style.css 3.79 kB 0 B
build/element/index.js 4.65 kB 0 B
build/escape-html/index.js 733 B 0 B
build/format-library/index.js 7.72 kB 0 B
build/format-library/style-rtl.css 547 B 0 B
build/format-library/style.css 548 B 0 B
build/hooks/index.js 2.13 kB 0 B
build/html-entities/index.js 621 B 0 B
build/i18n/index.js 3.56 kB 0 B
build/is-shallow-equal/index.js 711 B 0 B
build/keyboard-shortcuts/index.js 2.52 kB 0 B
build/keycodes/index.js 1.94 kB 0 B
build/list-reusable-blocks/index.js 3.11 kB 0 B
build/list-reusable-blocks/style-rtl.css 476 B 0 B
build/list-reusable-blocks/style.css 476 B 0 B
build/media-utils/index.js 5.33 kB 0 B
build/notices/index.js 1.79 kB 0 B
build/nux/index.js 3.4 kB 0 B
build/nux/style-rtl.css 671 B 0 B
build/nux/style.css 668 B 0 B
build/plugins/index.js 2.56 kB 0 B
build/primitives/index.js 1.41 kB 0 B
build/priority-queue/index.js 789 B 0 B
build/redux-routine/index.js 2.85 kB 0 B
build/rich-text/index.js 13.9 kB 0 B
build/server-side-render/index.js 2.71 kB 0 B
build/shortcode/index.js 1.7 kB 0 B
build/token-list/index.js 1.27 kB 0 B
build/url/index.js 4.06 kB 0 B
build/viewport/index.js 1.85 kB 0 B
build/warning/index.js 1.14 kB 0 B
build/wordcount/index.js 1.17 kB 0 B

compressed-size-action

@pento pento changed the title File Block: Add support for PDFs to be embedded. File Block: Add support for embedding PDFs Jul 29, 2020
@pento
Copy link
Member Author

pento commented Jul 29, 2020

I've been investigating what can be done for browsers that don't support embedded PDFs. There's no good option here.

Broadly speaking, browsers running on mobile devices are the ones that have a problem.

  • Chrome on Android renders a big black block with an "Open" button in the middle, for downloading and viewing the PDF in the PDF reader app.
  • Firefox on Android renders a blank space, but there is an extension which can be installed to add embedded PDF support. (The extension is no longer supported on the latest release of Firefox for Android.)
  • Everything on iOS renders the first page of the PDF, stretched to fit the size of the container element.

Unfortunately, there's no such thing as reliable feature detection for embedded PDF support, which gives us a few options:

  • Leave it as is, the major mobile browsers will just have suboptimal (but still usable) behaviour.
  • Use PDF.js to render PDFs, which will work everywhere, but it's a big download to be adding to all page loads.
  • Use user agent detection to determine if the browser probably doesn't support inline PDFs.

1c40e28 implements the third option, but I'm interested in arguments either way. 🙂

@pento pento marked this pull request as ready for review July 29, 2020 07:43
@pento pento added Needs Design Feedback Needs general design feedback. Needs Technical Feedback Needs testing from a developer perspective. Needs Testing Needs further testing to be confirmed. labels Jul 29, 2020
@pento
Copy link
Member Author

pento commented Jul 30, 2020

The help text is a little bit wordy, I'd appreciate some thoughts on making it less so.

@pento pento added the Needs Copy Review Needs review of user-facing copy (language, phrasing) label Jul 30, 2020
@michelleweber
Copy link

Do one of these work for you? Depending on what terms you prefer:

Note: Most mobile devices do not display embedded PDFs.

or

Most phone and tablet browsers won't display embedded PDFs.

@pento pento removed the Needs Copy Review Needs review of user-facing copy (language, phrasing) label Aug 3, 2020
@pento
Copy link
Member Author

pento commented Aug 3, 2020

Perfect, thanks for your help, @michelleweber!

@pento pento added this to the Gutenberg 8.8 milestone Aug 3, 2020
@aaronrobertshaw
Copy link
Contributor

This tests well for me, especially in Chrome, Firefox, Safari and Edge on MacOS.

IE11 on a Windows 10 VM with the Adobe Acrobat Reader and plugin installed would try to embed the PDF but appear to get stuck on the "initializing" display of the embedded object. Testing via Browserstack using Windows 10 and IE11 everything worked as expected. So it might have been something funky with my VM.

The various mobile and tablet browsers I could test, both on iOS and Android, worked as described.

@pento pento requested a review from a team August 9, 2020 23:40
function render_block_core_file( $attributes, $content ) {
$script = '';
if ( ! empty( $attributes['showInlineEmbed'] ) ) {
$script = <<<HTML
Copy link
Member

@swissspidy swissspidy Aug 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this script not an external script that is set as WP_Block_Type::$script when registering the block type below? Or alternatively, why not make it an external script and call wp_enqueue_script if ! empty( $attributes['showInlineEmbed'] )?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, as an external script it can be de-duped with packages/block-library/src/file/utils.js

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wp_enqueue_script() is probably the best option for de-duplicating the code, but I'm not aware of that method being used for any other blocks. (Or even the script property being used, for that matter.)

It seems like it would need a special case to keep it unbundled, and possibly some additional magic when it's merged to Core?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2b239f3 is a brief exploration of this: I don't mind it for this PR, I'm not wild about it as a generic solution.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see render_callback as a function that the sole purpose is to render (return) the content of the block and not trigger a side effect elsewhere. Using wp_enqueue_script creates an indirection that is very hard to follow.

I think a lot of people ask ways for providing frontend scripts for blocks and it could be a property in register_block_type (the equivalent to editor_script => frontend_script).

For the purpose of this PR specifically, I don't mind the hack, whether it's inline or wp_enqueue_script, both are not ideal solution for me but ok.

@mapk
Copy link
Contributor

mapk commented Aug 11, 2020

I'm really digging this embed viewer! 👍 I ran through some quick tests.

Embed reacts a little funky with alignments

alignments

Viewer menu is lost at minimum height

pdf-viewer

Embed is lost when grouping the block

grouping

@pento
Copy link
Member Author

pento commented Aug 11, 2020

Thanks for the testing, @mapk!

Embed reacts a little funky with alignments
Embed is lost when grouping the block

These both had the same root cause, fixed in 5739c88.

Viewer menu is lost at minimum height

This appears to be a bug in Chrome's default PDF viewer. They're working on an upgrade to the PDF viewer (you can see it by installing Chrome Canary and enabling this flag: chrome://flags/#pdf-viewer-update) which includes a fix for this.

@mapk
Copy link
Contributor

mapk commented Aug 12, 2020

Thanks @pento! Just to clarify, we don't have any control over the browser-based embed UI, correct? The colors (dark grey) and icons are all beyond our control.

If that's the case, this looks good to me. Adding an embed option to this block is a cool feature that I imagine will be useful for many. :)

@pento
Copy link
Member Author

pento commented Aug 13, 2020

Just to clarify, we don't have any control over the browser-based embed UI, correct? The colors (dark grey) and icons are all beyond our control.

That's correct, the embed UI is determined entirely by the browser (or in the case of Windows/IE, Adobe Acrobat 🙃).

@@ -33,10 +33,17 @@
"type": "string",
"source": "html",
"selector": "a[download]"
},
"showInlineEmbed": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we call it "embed" or "preview"? I mean it's not that important but we could the same for like images, text .... any file that can be previewed. Something like "quick view" in MacOS

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

showPreview or displayPreview perhaps?

}
},
"supports": {
"anchor": true,
"align": true
}
},
"script": "utils.js"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is doing?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems it's a way to tell pack to generate a separate script? Why not just a package because that's our way of doing this in Gutenberg?

Alternatively, if we implement the frontend_script proposal, we could introduce a convention like this (I see it more as a file in the block folder with the property here though). Having the property here will persist in the block registration... which I think is confusing.

@paaljoachim
Copy link
Contributor

Hey Gary @pento
How is this PR coming along?

@mapk mapk added the [Status] Stale Gives the original author opportunity to update before closing. Can be reopened as needed. label Dec 8, 2020
@johngodley
Copy link
Contributor

Noting that I've seen Safari 14 on Big Sur have issues with displaying a PDF via object and it sometimes freezes the page. The issue is caused by the experimental browser feature 'incremental pdf loading', which seems to be enabled by default.

I don't know if it also applies to this PR, but thought it worth mentioning for testing.

Base automatically changed from master to trunk March 1, 2021 15:43
pento added a commit that referenced this pull request Apr 15, 2021
@pento
Copy link
Member Author

pento commented Apr 15, 2021

Since #30341 landed, the webpack changes are no longer needed. It was easier to just create a new branch, rather than trying to rebase this one, so I'm closing this PR in favour of #30857.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] File Affects the File Block Needs Design Feedback Needs general design feedback. Needs Technical Feedback Needs testing from a developer perspective. Needs Testing Needs further testing to be confirmed. [Status] Stale Gives the original author opportunity to update before closing. Can be reopened as needed. [Type] Feature New feature to highlight in changelogs.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add block: Document/PDF with Preview
8 participants