Skip to content

Commit

Permalink
Allow overriding of imageResourcesPath (wojtekmaj#728)
Browse files Browse the repository at this point in the history
* Allow overriding of imageResourcesPath

* Add tests

* Update README.md
  • Loading branch information
hchevalier authored and wojtekmaj committed Feb 14, 2021
1 parent b45f9dd commit 59f66f1
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 2 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ Loads a document passed using `file` prop.
|error|What the component should display in case of an error.|`"Failed to load PDF file."`|<ul><li>String:<br />`"An error occurred!"`</li><li>React element:<br />`<div>An error occurred!</div>`</li><li>Function:<br />`this.renderError`</li></ul>|
|externalLinkTarget|Link target for external links rendered in annotations.|unset, which means that default behavior will be used|One of valid [values for `target` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#Attributes).<ul><li>`"_self"`</li><li>`"_blank"`</li><li>`"_parent"`</li><li>`"_top"`</li></ul>
|file|What PDF should be displayed.<br />Its value can be an URL, a file (imported using `import ... from ...` or from file input form element), or an object with parameters (`url` - URL; `data` - data, preferably Uint8Array; `range` - PDFDataRangeTransport; `httpHeaders` - custom request headers, e.g. for authorization), `withCredentials` - a boolean to indicate whether or not to include cookies in the request (defaults to `false`).<br />**Warning**: Since equality check (`===`) is used to determine if `file` object has changed, it must be memoized by setting it in component's state, `useMemo` or other similar technique.|n/a|<ul><li>URL:<br />`"http://example.com/sample.pdf"`</li><li>File:<br />`import sample from '../static/sample.pdf'` and then<br />`sample`</li><li>Parameter object:<br />`{ url: 'http://example.com/sample.pdf', httpHeaders: { 'X-CustomHeader': '40359820958024350238508234' }, withCredentials: true }`</ul>|
|imageResourcesPath|The path used to prefix the src attributes of annotation SVGs.|n/a (pdf.js will fallback to an empty string)|`"/public/images/"`|
|inputRef|A prop that behaves like [ref](https://reactjs.org/docs/refs-and-the-dom.html), but it's passed to main `<div>` rendered by `<Document>` component.|n/a|<ul><li>Function:<br />`(ref) => { this.myDocument = ref; }`</li><li>Ref created using `React.createRef`:<br />`this.ref = React.createRef();`<br />…<br />`inputRef={this.ref}`</li><li>Ref created using `React.useRef`:<br />`const ref = React.useRef();`<br />…<br />`inputRef={ref}`</li></ul>|
|loading|What the component should display while loading.|`"Loading PDF…"`|<ul><li>String:<br />`"Please wait!"`</li><li>React element:<br />`<div>Please wait!</div>`</li><li>Function:<br />`this.renderLoader`</li></ul>|
|noData|What the component should display in case of no data.|`"No PDF file specified."`|<ul><li>String:<br />`"Please select a file."`</li><li>React element:<br />`<div>Please select a file.</div>`</li><li>Function:<br />`this.renderNoData`</li></ul>|
Expand All @@ -248,6 +249,7 @@ Displays a page. Should be placed inside `<Document />`. Alternatively, it can h
|customTextRenderer|A function that customizes how a text layer is rendered. Passes itext item and index for item.|n/a|`({ str, itemIndex }) => { return (<mark>{str}</mark>) }`|
|error|What the component should display in case of an error.|`"Failed to load the page."`|<ul><li>String:<br />`"An error occurred!"`</li><li>React element:<br />`<div>An error occurred!</div>`</li><li>Function:<br />`this.renderError`</li></ul>|
|height|Page height. If neither `height` nor `width` are defined, page will be rendered at the size defined in PDF. If you define `width` and `height` at the same time, `height` will be ignored. If you define `height` and `scale` at the same time, the height will be multiplied by a given factor.|Page's default height|`300`|
|imageResourcesPath|The path used to prefix the src attributes of annotation SVGs.|n/a (pdf.js will fallback to an empty string)|`"/public/images/"`|
|inputRef|A prop that behaves like [ref](https://reactjs.org/docs/refs-and-the-dom.html), but it's passed to main `<div>` rendered by `<Page>` component.|n/a|<ul><li>Function:<br />`(ref) => { this.myPage = ref; }`</li><li>Ref created using `React.createRef`:<br />`this.ref = React.createRef();`<br />…<br />`inputRef={this.ref}`</li><li>Ref created using `React.useRef`:<br />`const ref = React.useRef();`<br />…<br />`inputRef={ref}`</li></ul>|
|loading|What the component should display while loading.|`"Loading page…"`|<ul><li>String:<br />`"Please wait!"`</li><li>React element:<br />`<div>Please wait!</div>`</li><li>Function:<br />`this.renderLoader`</li></ul>|
|noData|What the component should display in case of no data.|`"No page specified."`|<ul><li>String:<br />`"Please select a page."`</li><li>React element:<br />`<div>Please select a page.</div>`</li><li>Function:<br />`this.renderNoData`</li></ul>|
Expand Down
Binary file added __mocks__/_pdf3.pdf
Binary file not shown.
4 changes: 3 additions & 1 deletion src/Document.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,11 @@ export default class Document extends PureComponent {

get childContext() {
const { linkService, registerPage, unregisterPage } = this;
const { renderMode, rotate } = this.props;
const { imageResourcesPath, renderMode, rotate } = this.props;
const { pdf } = this.state;

return {
imageResourcesPath,
linkService,
pdf,
registerPage,
Expand Down Expand Up @@ -382,6 +383,7 @@ Document.propTypes = {
className: isClassName,
error: isFunctionOrNode,
file: isFile,
imageResourcesPath: PropTypes.string,
inputRef: isRef,
loading: isFunctionOrNode,
noData: isFunctionOrNode,
Expand Down
1 change: 1 addition & 0 deletions src/Page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ PageInternal.propTypes = {
customTextRenderer: PropTypes.func,
error: isFunctionOrNode,
height: PropTypes.number,
imageResourcesPath: PropTypes.string,
inputRef: isRef,
loading: isFunctionOrNode,
noData: isFunctionOrNode,
Expand Down
10 changes: 9 additions & 1 deletion src/Page/AnnotationLayer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,19 @@ export class AnnotationLayerInternal extends PureComponent {
return;
}

const { linkService, page, renderInteractiveForms } = this.props;
const {
imageResourcesPath,
linkService,
page,
renderInteractiveForms,
} = this.props;

const viewport = this.viewport.clone({ dontFlip: true });

const parameters = {
annotations,
div: this.annotationLayer,
imageResourcesPath,
linkService,
page,
renderInteractiveForms,
Expand Down Expand Up @@ -138,6 +145,7 @@ export class AnnotationLayerInternal extends PureComponent {
}

AnnotationLayerInternal.propTypes = {
imageResourcesPath: PropTypes.string,
linkService: isLinkService.isRequired,
onGetAnnotationsError: PropTypes.func,
onGetAnnotationsSuccess: PropTypes.func,
Expand Down
54 changes: 54 additions & 0 deletions src/Page/AnnotationLayer.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from '../../test-utils';

const pdfFile = loadPDF('./__mocks__/_pdf.pdf');
const annotatedPdfFile = loadPDF('./__mocks__/_pdf3.pdf');

describe('AnnotationLayer', () => {
const linkService = new LinkService({ eventBus });
Expand Down Expand Up @@ -219,5 +220,58 @@ describe('AnnotationLayer', () => {
expect(viewport.scale).toEqual(scale);
});
});

it('renders annotations with the default imageResourcesPath given no imageResourcesPath', async () => {
const pdf = await pdfjs.getDocument({ data: annotatedPdfFile.arrayBuffer }).promise;
const annotatedPage = await pdf.getPage(1);

const {
func: onRenderAnnotationLayerSuccess, promise: onRenderAnnotationLayerSuccessPromise,
} = makeAsyncCallback();
const imageResourcesPath = '';
const desiredImageTagRegExp = new RegExp(`<img[^>]+src="${imageResourcesPath}annotation-note.svg"`);

const component = mount(
<AnnotationLayer
linkService={linkService}
onRenderAnnotationLayerSuccess={onRenderAnnotationLayerSuccess}
page={annotatedPage}
/>,
);

expect.assertions(1);
return onRenderAnnotationLayerSuccessPromise.then(() => {
component.update();
const stringifiedAnnotationLayerNode = component.html();
expect(stringifiedAnnotationLayerNode).toMatch(desiredImageTagRegExp);
});
});

it('renders annotations with the specified imageResourcesPath given imageResourcesPath', async () => {
const pdf = await pdfjs.getDocument({ data: annotatedPdfFile.arrayBuffer }).promise;
const annotatedPage = await pdf.getPage(1);

const {
func: onRenderAnnotationLayerSuccess, promise: onRenderAnnotationLayerSuccessPromise,
} = makeAsyncCallback();
const imageResourcesPath = '/public/images/';
const desiredImageTagRegExp = new RegExp(`<img[^>]+src="${imageResourcesPath}annotation-note.svg"`);

const component = mount(
<AnnotationLayer
imageResourcesPath={imageResourcesPath}
linkService={linkService}
onRenderAnnotationLayerSuccess={onRenderAnnotationLayerSuccess}
page={annotatedPage}
/>,
);

expect.assertions(1);
return onRenderAnnotationLayerSuccessPromise.then(() => {
component.update();
const stringifiedAnnotationLayerNode = component.html();
expect(stringifiedAnnotationLayerNode).toMatch(desiredImageTagRegExp);
});
});
});
});

0 comments on commit 59f66f1

Please sign in to comment.