diff --git a/src/lib/ThumbnailsSidebar.js b/src/lib/ThumbnailsSidebar.js index 8ef30e887..e8af099b9 100644 --- a/src/lib/ThumbnailsSidebar.js +++ b/src/lib/ThumbnailsSidebar.js @@ -4,12 +4,14 @@ import { CLASS_HIDDEN } from './constants'; import BoundedCache from './BoundedCache'; const CLASS_BOX_PREVIEW_THUMBNAIL = 'bp-thumbnail'; +const CLASS_BOX_PREVIEW_THUMBNAIL_NAV = 'bp-thumbnail-nav'; const CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE = 'bp-thumbnail-image'; const CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE_LOADED = 'bp-thumbnail-image-loaded'; const CLASS_BOX_PREVIEW_THUMBNAIL_IS_SELECTED = 'bp-thumbnail-is-selected'; const CLASS_BOX_PREVIEW_THUMBNAIL_PAGE_NUMBER = 'bp-thumbnail-page-number'; -const DEFAULT_THUMBNAILS_SIDEBAR_WIDTH = 150; +const DEFAULT_THUMBNAILS_SIDEBAR_WIDTH = 127; // 200px sidebar width - 25px margin right, - 40px for page number - 8px for border const THUMBNAIL_MARGIN = 15; +const BORDER_WIDTH = 8; class ThumbnailsSidebar { /** @property {HTMLElement} - The anchor element for this ThumbnailsSidebar */ @@ -69,9 +71,10 @@ class ThumbnailsSidebar { // Only care about clicks on the thumbnail element itself. // The image and page number have pointer-events: none so // any click should be the thumbnail element itself. - if (target.classList.contains(CLASS_BOX_PREVIEW_THUMBNAIL)) { + if (target.classList.contains(CLASS_BOX_PREVIEW_THUMBNAIL_NAV)) { + const thumbnailEl = target.parentNode; // Get the page number - const { bpPageNum: pageNumStr } = target.dataset; + const { bpPageNum: pageNumStr } = thumbnailEl.dataset; const pageNum = parseInt(pageNumStr, 10); if (this.onClickHandler) { @@ -145,7 +148,7 @@ class ThumbnailsSidebar { this.virtualScroller.init({ initialRowIndex: this.currentPage - 1, totalItems: this.pdfViewer.pagesCount, - itemHeight: this.thumbnailHeight, + itemHeight: this.thumbnailHeight + BORDER_WIDTH, containerHeight: this.getContainerHeight(), margin: THUMBNAIL_MARGIN, renderItemFn: this.createPlaceholderThumbnail, @@ -193,16 +196,17 @@ class ThumbnailsSidebar { * not yet have the image of the page * * @param {number} itemIndex - The item index into the overall list (0 indexed) - * @return {HTMLElement} - thumbnail button element + * @return {HTMLElement} - thumbnail element */ createPlaceholderThumbnail(itemIndex) { - const thumbnailEl = document.createElement('button'); + const thumbnailEl = document.createElement('div'); const pageNum = itemIndex + 1; thumbnailEl.className = CLASS_BOX_PREVIEW_THUMBNAIL; - thumbnailEl.setAttribute('type', 'button'); thumbnailEl.dataset.bpPageNum = pageNum; thumbnailEl.appendChild(this.createPageNumber(pageNum)); + const thumbnailNav = this.createThumbnailNav(); + thumbnailEl.appendChild(thumbnailNav); if (pageNum === this.currentPage) { thumbnailEl.classList.add(CLASS_BOX_PREVIEW_THUMBNAIL_IS_SELECTED); @@ -212,13 +216,23 @@ class ThumbnailsSidebar { // the second render image pass const cachedImage = this.thumbnailImageCache.get(itemIndex); if (cachedImage && !cachedImage.inProgress) { - thumbnailEl.appendChild(cachedImage.image); + thumbnailNav.appendChild(cachedImage.image); thumbnailEl.classList.add(CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE_LOADED); } return thumbnailEl; } + /** + * Creates the thumbnail navigation element + * @return {HTMLElement} - thumbnail anchor element + */ + createThumbnailNav() { + const thumbnailNav = document.createElement('a'); + thumbnailNav.className = CLASS_BOX_PREVIEW_THUMBNAIL_NAV; + return thumbnailNav; + } + /** * Request the thumbnail image to be made * @@ -231,7 +245,8 @@ class ThumbnailsSidebar { this.createThumbnailImage(itemIndex).then((imageEl) => { // Promise will resolve with null if create image request was already in progress if (imageEl) { - thumbnailEl.appendChild(imageEl); + // Appends to the lastChild which should be the thumbnail nav element + thumbnailEl.lastChild.appendChild(imageEl); thumbnailEl.classList.add(CLASS_BOX_PREVIEW_THUMBNAIL_IMAGE_LOADED); } diff --git a/src/lib/__tests__/ThumbnailsSidebar-test.js b/src/lib/__tests__/ThumbnailsSidebar-test.js index 95f0f0fed..0ef1478b4 100644 --- a/src/lib/__tests__/ThumbnailsSidebar-test.js +++ b/src/lib/__tests__/ThumbnailsSidebar-test.js @@ -103,7 +103,7 @@ describe('ThumbnailsSidebar', () => { return pagePromise.then(() => { expect(stubs.getViewport).to.be.called; - expect(thumbnailsSidebar.scale).to.be.equal(15); // DEFAULT_THUMBNAILS_SIDEBAR_WIDTH / width + expect(thumbnailsSidebar.scale).to.be.equal(12.7); // DEFAULT_THUMBNAILS_SIDEBAR_WIDTH / width expect(thumbnailsSidebar.pageRatio).to.be.equal(1); expect(stubs.vsInit).to.be.called; }); @@ -212,7 +212,7 @@ describe('ThumbnailsSidebar', () => { stubs.addClass = sandbox.stub(); const thumbnailEl = { - appendChild: stubs.appendChild, + lastChild: { appendChild: stubs.appendChild }, classList: { add: stubs.addClass } }; @@ -282,7 +282,7 @@ describe('ThumbnailsSidebar', () => { stubs.getViewport.withArgs(1).returns({ width: 10, height: 10 }); stubs.render.returns(Promise.resolve()); - const expScale = 15; // Should be DEFAULT_THUMBNAILS_SIDEBAR_WIDTH(150) / 10 + const expScale = 12.7; // Should be DEFAULT_THUMBNAILS_SIDEBAR_WIDTH / 10 return thumbnailsSidebar.getThumbnailDataURL(1).then(() => { expect(stubs.getPage).to.be.called; @@ -299,9 +299,10 @@ describe('ThumbnailsSidebar', () => { stubs.getViewport.withArgs(1).returns({ width: 10, height: 20 }); stubs.render.returns(Promise.resolve()); - const expScale = 7.5; // Should be 7.5 instead of 15 because the viewport ratio above is 0.5 instead of 1 + const expScale = 6.3; // Should be 6.3 instead of 12.7 because the viewport ratio above is 0.5 instead of 1 + // and because canvas width is integer, so 63.5 becomes 63 - return thumbnailsSidebar.createThumbnailImage(0).then(() => { + return thumbnailsSidebar.getThumbnailDataURL(0).then(() => { expect(stubs.getPage).to.be.called; expect(stubs.getViewport.withArgs(expScale)).to.be.called; }); @@ -310,6 +311,7 @@ describe('ThumbnailsSidebar', () => { describe('thumbnailClickHandler()', () => { let targetEl; + let parentEl; let evt; beforeEach(() => { @@ -317,9 +319,13 @@ describe('ThumbnailsSidebar', () => { stubs.preventDefault = sandbox.stub(); stubs.stopImmediatePropagation = sandbox.stub(); + parentEl = document.createElement('div'); + parentEl.dataset.bpPageNum = '3'; + targetEl = document.createElement('div'); - targetEl.classList.add('bp-thumbnail'); - targetEl.dataset.bpPageNum = '3'; + targetEl.classList.add('bp-thumbnail-nav'); + + parentEl.appendChild(targetEl); evt = { target: targetEl, @@ -339,7 +345,7 @@ describe('ThumbnailsSidebar', () => { }); it('should not call the onClickHandler if target is not thumbnail element', () => { - targetEl.classList.remove('bp-thumbnail'); + targetEl.classList.remove('bp-thumbnail-nav'); thumbnailsSidebar.thumbnailClickHandler(evt); expect(stubs.onClickHandler).not.to.be.called; diff --git a/src/lib/viewers/doc/_docBase.scss b/src/lib/viewers/doc/_docBase.scss index 049677a6e..8fefec099 100644 --- a/src/lib/viewers/doc/_docBase.scss +++ b/src/lib/viewers/doc/_docBase.scss @@ -10,55 +10,44 @@ $thumbnail-border-radius: 4px; } .bp-thumbnail { - align-items: center; - background-color: $d-eight; - border: 0; - border-radius: $thumbnail-border-radius; - cursor: pointer; display: flex; flex: 1 0 auto; - justify-content: center; - margin: 0 25px; + margin-right: 25px; padding: 0; position: relative; - width: 150px; } .bp-thumbnail-page-number { - background-color: $black; - border-radius: $thumbnail-border-radius; - bottom: 10px; - color: $white; + color: $twos; + flex: 0 0 34px; font-size: 11px; - left: 50%; line-height: 16px; - opacity: .7; - padding: 0 5px; + margin: 4px 6px 0 0; pointer-events: none; - position: absolute; - transform: translateX(-50%); + text-align: right; + width: 34px; + } + + .bp-thumbnail-nav { + background-color: $d-eight; + border: $thumbnail-border-radius solid $ffive; + border-radius: $thumbnail-border-radius; + cursor: pointer; + flex: 1 0 auto; + padding: 0; + overflow: hidden; + width: 134px; } .bp-thumbnail-image { background-position: center; background-repeat: no-repeat; background-size: contain; - border-radius: $thumbnail-border-radius; pointer-events: none; } - // Applies a border *outside* the thumbnail button itself rather than - // contributing to the width of the button and shrinking the thumbnail - // image - .bp-thumbnail.bp-thumbnail-is-selected::after { - border: 4px solid $fours; - border-radius: $thumbnail-border-radius; - bottom: -2px; - content: ''; - left: -2px; - position: absolute; - right: -2px; - top: -2px; + .bp-thumbnail.bp-thumbnail-is-selected .bp-thumbnail-nav { + border-color: $fours; } }