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

fix(a11y): screen reader support for view only file preview #1495

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/lib/viewers/doc/DocBaseViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ class DocBaseViewer extends BaseViewer {

this.viewerEl = this.docEl.appendChild(document.createElement('div'));
this.viewerEl.classList.add('pdfViewer');

this.loadTimeout = LOAD_TIMEOUT_MS;

this.startPageNum = this.getStartPage(this.startAt);
Expand Down Expand Up @@ -795,7 +796,15 @@ class DocBaseViewer extends BaseViewer {
const { AnnotationMode: PDFAnnotationMode = {} } = this.pdfjsLib;
const assetUrlCreator = createAssetUrlCreator(location);
const hasDownload = checkPermission(file, PERMISSION_DOWNLOAD);
const hasTextLayer = hasDownload && !this.getViewerOption('disableTextLayer');
arturfrombox marked this conversation as resolved.
Show resolved Hide resolved
const hasTextLayer = !this.getViewerOption('disableTextLayer');
const enabledTextLayerMode = hasDownload
? PDFJS_TEXT_LAYER_MODE.ENABLE
: PDFJS_TEXT_LAYER_MODE.ENABLE_PERMISSIONS; // This mode will prevent default behavior for copy events in the TextLayerBuilder

// Text layer should be rendered for a11y reasons thats why we will block user from selecting content when no download permissions was granted
if (!hasDownload) {
this.viewerEl.classList.add('pdfViewer--viewOnly');
}

return new PdfViewerClass({
annotationMode: PDFAnnotationMode.ENABLE, // Show annotations, but not forms
Expand All @@ -806,7 +815,7 @@ class DocBaseViewer extends BaseViewer {
linkService: this.pdfLinkService,
maxCanvasPixels: this.isMobile ? MOBILE_MAX_CANVAS_SIZE : -1,
renderInteractiveForms: false, // Enabling prevents unverified signatures from being displayed
textLayerMode: hasTextLayer ? PDFJS_TEXT_LAYER_MODE.ENABLE : PDFJS_TEXT_LAYER_MODE.DISABLE,
textLayerMode: hasTextLayer ? enabledTextLayerMode : PDFJS_TEXT_LAYER_MODE.DISABLE,
});
}

Expand Down
40 changes: 31 additions & 9 deletions src/lib/viewers/doc/__tests__/DocBaseViewer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1140,43 +1140,65 @@ describe('src/lib/viewers/doc/DocBaseViewer', () => {
});
});

test('should enable the text layer based on download permissions', () => {
test('should enable the text layer if the user is on mobile', () => {
docBase.isMobile = true;
stubs.checkPermission.mockReturnValueOnce(true);

return docBase.initViewer('').then(() => {
expect(stubs.checkPermission).toBeCalledWith(docBase.options.file, PERMISSION_DOWNLOAD);
expect(stubs.getViewerOption).toBeCalledWith('disableTextLayer');
// Text Layer mode 1 = enabled
expect(stubs.pdfViewerClass).toBeCalledWith(expect.objectContaining({ textLayerMode: 1 }));
});
});

test('should enable the text layer if the user is on mobile', () => {
docBase.isMobile = true;
test('should add view only class if user does not have download permissions', () => {
docBase.containerEl = containerEl;
stubs.checkPermission.mockReturnValueOnce(false);

return docBase.initViewer('').then(() => {
expect(stubs.checkPermission).toBeCalledWith(docBase.options.file, PERMISSION_DOWNLOAD);
expect(docBase.viewerEl).toHaveClass('pdfViewer--viewOnly');
});
});

test('should not add view only class if user has download permissions', () => {
docBase.containerEl = containerEl;
stubs.checkPermission.mockReturnValueOnce(true);

return docBase.initViewer('').then(() => {
expect(stubs.checkPermission).toBeCalledWith(docBase.options.file, PERMISSION_DOWNLOAD);
expect(docBase.viewerEl).not.toHaveClass('pdfViewer--viewOnly');
});
});

test('should use proper text layer mode if user has download permissions and disableTextLayer viewer option is not set', () => {
stubs.getViewerOption.mockReturnValue(false);
stubs.checkPermission.mockReturnValueOnce(true);

return docBase.initViewer('').then(() => {
expect(stubs.checkPermission).toBeCalledWith(docBase.options.file, PERMISSION_DOWNLOAD);
expect(stubs.getViewerOption).toBeCalledWith('disableTextLayer');
// Text Layer mode 1 = enabled
expect(stubs.pdfViewerClass).toBeCalledWith(expect.objectContaining({ textLayerMode: 1 }));
});
});

test('should disable the text layer based on download permissions', () => {
test('should use proper text layer mode if user does not have download permissions and disableTextLayer viewer option is not set', () => {
stubs.getViewerOption.mockReturnValue(false);
stubs.checkPermission.mockReturnValueOnce(false);

return docBase.initViewer('').then(() => {
expect(stubs.checkPermission).toBeCalledWith(docBase.options.file, PERMISSION_DOWNLOAD);
// Text Layer mode 0 = disabled
expect(stubs.pdfViewerClass).toBeCalledWith(expect.objectContaining({ textLayerMode: 0 }));
expect(stubs.getViewerOption).toBeCalledWith('disableTextLayer');
// Text Layer mode 2 = enabled permissions
expect(stubs.pdfViewerClass).toBeCalledWith(expect.objectContaining({ textLayerMode: 2 }));
});
});

test('should disable the text layer if disableTextLayer viewer option is set', () => {
stubs.checkPermission.mockReturnValueOnce(true);
stubs.getViewerOption.mockReturnValue(true);

return docBase.initViewer('').then(() => {
expect(stubs.checkPermission).toBeCalledWith(docBase.options.file, PERMISSION_DOWNLOAD);
expect(stubs.getViewerOption).toBeCalledWith('disableTextLayer');
// Text Layer mode 0 = disabled
expect(stubs.pdfViewerClass).toBeCalledWith(expect.objectContaining({ textLayerMode: 0 }));
Expand Down
11 changes: 11 additions & 0 deletions src/lib/viewers/doc/_docBase.scss
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,17 @@ $thumbnail-sidebar-width: 191px; // Extra pixel to account for sidebar border
}
}

.pdfViewer {
&.pdfViewer--viewOnly {
.textLayer {
span {
arturfrombox marked this conversation as resolved.
Show resolved Hide resolved
cursor: unset;
user-select: none;
}
}
}
}

.textLayer {
caret-color: black; // Required for caret navigation on transparent text
top: $pdfjs-page-padding;
Expand Down