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

Show a warning when PDF does not have selectable text #2623

Merged
merged 5 commits into from
Oct 16, 2020

Conversation

robertknight
Copy link
Member

@robertknight robertknight commented Oct 9, 2020

This is an initial solution for hypothesis/product-backlog#1081. It adds a banner to the top of the PDF viewer when the current PDF does not contain any selectable text.

Current design (updated 2020-10-16):

pdf-no-text-v2

The "OCR-optimized" text links to https://web.hypothes.is/help/how-to-ocr-optimize-pdfs/.

@robertknight robertknight force-pushed the no-selectable-text-warning branch from 28948db to df229ae Compare October 9, 2020 13:07
resolve(pdfViewer.getPageView(pageIndex));
};
document.addEventListener('pagesloaded', onPagesLoaded);
pdfViewer.eventBus.on('pagesloaded', onPagesLoaded);
Copy link
Member Author

Choose a reason for hiding this comment

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

This fixes a compatibility issue with new versions of PDF.js that we hadn't noticed before. PDF viewer events are no longer emitted as DOM events. It should be extracted into a separate PR and shipped first.

@robertknight robertknight force-pushed the no-selectable-text-warning branch from df229ae to 8307002 Compare October 14, 2020 13:09
@codecov
Copy link

codecov bot commented Oct 14, 2020

Codecov Report

Merging #2623 into master will increase coverage by 0.03%.
The diff coverage is 100.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2623      +/-   ##
==========================================
+ Coverage   97.40%   97.44%   +0.03%     
==========================================
  Files         200      200              
  Lines        7503     7540      +37     
  Branches     1653     1656       +3     
==========================================
+ Hits         7308     7347      +39     
+ Misses        195      193       -2     
Impacted Files Coverage Δ
src/annotator/anchoring/pdf.js 99.44% <100.00%> (+0.02%) ⬆️
src/annotator/plugin/pdf.js 91.66% <100.00%> (+9.84%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 77d3023...50cf4f8. Read the comment docs.

@lyzadanger
Copy link
Contributor

@robertknight I've pushed some commits that apply styling to the warning message. As of 152212e it looks like this:

image

The border width (borders are top and bottom only) is 2px currently. We can go to 3px, but it looks a little chunky.

robertknight and others added 4 commits October 16, 2020 14:23
 - Add `documentHasText` helper in `anchoring/pdf.js` which checks if
   the document appears to have selectable text

 - Add logic in `plugin/pdf.js` which uses the `documentHasText` helper
   to check whether the PDF has selectable text and display a banner
   above the PDF viewer if not

Fixes hypothesis/product-backlog#1081
This icon is an MIT-licensed SVG sourced from https://feathericons.com/
Divide up `toast-message` styling for resuability. Use its base
styles as a foundation for a full-width "banner" pattern.
@robertknight robertknight force-pushed the no-selectable-text-warning branch from 152212e to d435588 Compare October 16, 2020 13:24
@robertknight robertknight marked this pull request as ready for review October 16, 2020 13:31
Copy link
Contributor

@lyzadanger lyzadanger left a comment

Choose a reason for hiding this comment

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

Looking good.

const hasText = await pdfAnchoring.documentHasText();
this._showNoSelectableTextWarning(!hasText);
} catch (err) {
/* istanbul ignore next */
Copy link
Contributor

Choose a reason for hiding this comment

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

I suppose I could have used this approach to what we were discussing regarding #2646 and the guarding against arrays being of different lengths...

}

const mainContainer = /** @type {HTMLElement} */ (document.querySelector(
'#mainContainer'
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this OK as a literal here (i.e. is this selector used elsewhere and could it be maintained as a constant somewhere?)

Copy link
Member Author

Choose a reason for hiding this comment

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

This selector isn't referenced anywhere else. It could do with a comment explaining where the element comes from though.

if (!this._warningBanner) {
return;
}
const rect = this._warningBanner.getBoundingClientRect();
Copy link
Contributor

Choose a reason for hiding this comment

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

A comment here might not hurt—explaining that we're moving the main container down to accommodate the warning banner, right?

};

this._warningBanner = document.createElement('div');
this._warningBanner.className =
Copy link
Contributor

Choose a reason for hiding this comment

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

I'll acknowledge that these classnames could be...tidier.

// Update the banner when the window is resized or the Hypothesis
// sidebar is opened.
// @ts-ignore
new ResizeObserver(updateBannerHeight).observe(this._warningBanner);
Copy link
Contributor

Choose a reason for hiding this comment

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

ResizeObserver is supported in, it looks like, all of our target browsers save for Android's Firefox. Historically, we've used MutationObserver (broader/older support but more complex API) as a polyfill, see src/sidebar/util/observe-element-size — do we have a plan going forward?

Copy link
Member Author

@robertknight robertknight Oct 16, 2020

Choose a reason for hiding this comment

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

ResizeObserver was only recently introduced in Safari (13.1) which means it isn't available on older iOS devices. In older browsers the banner height will simply be static based on the window size when the client first loads. I think that's an acceptable failure mode.

So in summary - whether we need a fallback depends on the use case. For annotation cards it is more important to have a fallback for when ResizeObserver is not available.

Add comments to explain where the `#mainContainer` selector come from,
when the warning banner size may change and what happens in older
browsers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants