Skip to content

Commit

Permalink
Show warning banner above PDF if there is no selectable text
Browse files Browse the repository at this point in the history
  • Loading branch information
robertknight committed Oct 9, 2020
1 parent 7d0f474 commit 28948db
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 0 deletions.
16 changes: 16 additions & 0 deletions src/annotator/anchoring/pdf.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,22 @@ async function getPageView(pageIndex) {
return /** @type {PDFPageView} */ (pageView);
}

/**
* Return true if the document has selectable text.
*/
export async function documentHasText() {
const viewer = getPdfViewer();
let hasText = false;
for (let i = 0; i < viewer.pagesCount; i++) {
const pageText = await getPageTextContent(i);
if (pageText.trim().length > 0) {
hasText = true;
break;
}
}
return hasText;
}

/**
* Return the text of a given PDF page.
*
Expand Down
91 changes: 91 additions & 0 deletions src/annotator/plugin/pdf.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import debounce from 'lodash.debounce';
import { Fragment, createElement, render } from 'preact';

import * as pdfAnchoring from '../anchoring/pdf';
import Delegator from '../delegator';
Expand All @@ -12,6 +13,26 @@ import PDFMetadata from './pdf-metadata';
* @typedef {import('../../types/annotator').HypothesisWindow} HypothesisWindow
*/

/**
* A banner shown at the top of the PDF viewer if the PDF cannot be annotated
* by Hypothesis.
*/
function WarningBanner() {
return (
<Fragment>
This PDF does not contain selectable text. To annotate it with Hypothesis
you will need to{' '}
<a
target="_blank"
rel="noreferrer"
href="https://web.hypothes.is/help/how-to-ocr-optimize-pdfs/"
>
OCR-optimize it.
</a>
</Fragment>
);
}

export default class PDF extends Delegator {
/**
* @param {Annotator} annotator
Expand All @@ -35,6 +56,16 @@ export default class PDF extends Delegator {
childList: true,
subtree: true,
});

/**
* A banner shown at the top of the PDF viewer warning the user if the PDF
* is not suitable for use with Hypothesis.
*
* @type {HTMLElement|null}
*/
this._warningBanner = null;

this._checkForSelectableText();
}

destroy() {
Expand All @@ -50,6 +81,66 @@ export default class PDF extends Delegator {
return this.pdfMetadata.getMetadata();
}

/**
* Check whether the PDF has selectable text and show a warning if not.
*/
async _checkForSelectableText() {
// Wait for PDF to load.
try {
await this.uri();
} catch (e) {
return;
}

try {
const hasText = await pdfAnchoring.documentHasText();
this._showNoSelectableTextWarning(!hasText);
} catch (err) {
console.warn('Unable to check for text in PDF:', err);
}
}

/**
* Set whether the warning about a PDF's suitability for use with Hypothesis
* is shown.
*
* @param {boolean} showWarning
*/
_showNoSelectableTextWarning(showWarning) {
if (!showWarning) {
this._warningBanner?.remove();
this._warningBanner = null;
return;
}

const mainContainer = /** @type {HTMLElement} */ (document.querySelector(
'#mainContainer'
));

const updateBannerHeight = () => {
if (!this._warningBanner) {
return;
}
const rect = this._warningBanner.getBoundingClientRect();
mainContainer.style.top = rect.height + 'px';
this._warningBanner.style.top = -rect.height + 'px';
};

this._warningBanner = document.createElement('div');
this._warningBanner.className = 'annotator-warning-banner';
mainContainer.appendChild(this._warningBanner);
render(<WarningBanner />, this._warningBanner);

// @ts-expect-error - TS is missing `ResizeObserver`
if (typeof ResizeObserver !== 'undefined') {
// Update the banner when the window is resized or the Hypothesis
// sidebar is opened.
// @ts-ignore
new ResizeObserver(updateBannerHeight).observe(this._warningBanner);
}
updateBannerHeight();
}

// This method (re-)anchors annotations when pages are rendered and destroyed.
_update() {
// A list of annotations that need to be refreshed.
Expand Down
19 changes: 19 additions & 0 deletions src/styles/annotator/annotator.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SASS entry point for annotator styling

@use "sass:meta";
@use "sass:color" as color;

@use '../variables' as var;
@use '../mixins/reset';

Expand Down Expand Up @@ -81,6 +83,23 @@
transition: none !important;
}

.annotator-warning-banner {
background-color: var.$color-highlight;
border-bottom: 3px solid color.adjust(var.$color-highlight, $lightness: -40%);
color: black;
font-size: 12pt;
font-weight: bold;

position: absolute;
left: 0;
top: 0;
right: 0;

padding: 10px 5px;

z-index: 10000;
}

/*
Mobile layout
240-479 px
Expand Down

0 comments on commit 28948db

Please sign in to comment.