Commit 6d21e86b authored by Daniel Hosseinian's avatar Daniel Hosseinian Committed by Commit Bot

PDF Viewer Update: Detect when to request thumbnails

Add an IntersectionObserver to the thumbnail bar. When the thumbnails
scroll into the observable area, fire an event to request the thumbnail.

The requests are not handled yet.

Bug: 652400
Change-Id: I6a3dc3ce59304dca20b2d8d828a97e98a3388b92
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2430443
Commit-Queue: Daniel Hosseinian <dhoss@chromium.org>
Reviewed-by: default avatardpapad <dpapad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#810879}
parent 4aa035ad
...@@ -3,12 +3,17 @@ ...@@ -3,12 +3,17 @@
box-sizing: border-box; box-sizing: border-box;
height: 100%; height: 100%;
overflow: auto; overflow: auto;
padding-bottom: 24px; padding: 24px 0;
text-align: center; text-align: center;
} }
viewer-thumbnail + viewer-thumbnail {
padding-top: 24px;
}
</style> </style>
<div id="thumbnails"> <div id="thumbnails">
<template is="dom-repeat" items="[[pageNumbers_]]"> <template is="dom-repeat" items="[[pageNumbers_]]"
on-dom-change="onDomChange_">
<viewer-thumbnail is-active="[[isActivePage_(item, activePage)]]" <viewer-thumbnail is-active="[[isActivePage_(item, activePage)]]"
page-number="[[item]]"> page-number="[[item]]">
</viewer-thumbnail> </viewer-thumbnail>
......
...@@ -2,10 +2,11 @@ ...@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import './viewer-thumbnail.js'; import {assert} from 'chrome://resources/js/assert.m.js';
import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {html, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {ViewerThumbnailElement} from './viewer-thumbnail.js';
export class ViewerThumbnailBarElement extends PolymerElement { export class ViewerThumbnailBarElement extends PolymerElement {
static get is() { static get is() {
return 'viewer-thumbnail-bar'; return 'viewer-thumbnail-bar';
...@@ -29,6 +30,38 @@ export class ViewerThumbnailBarElement extends PolymerElement { ...@@ -29,6 +30,38 @@ export class ViewerThumbnailBarElement extends PolymerElement {
}; };
} }
ready() {
super.ready();
const thumbnailsDiv = this.shadowRoot.querySelector('#thumbnails');
assert(thumbnailsDiv);
/** @private {!IntersectionObserver} */
this.intersectionObserver_ = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (!entry.isIntersecting) {
// TODO(crbug.com/652400): Unpaint thumbnails.
return;
}
const thumbnail = /** @type {!ViewerThumbnailElement} */ (entry.target);
if (thumbnail.hasAttribute('pending')) {
return;
}
thumbnail.toggleAttribute('pending');
this.dispatchEvent(new CustomEvent(
'paint-thumbnail',
{detail: thumbnail, bubbles: true, composed: true}));
});
}, {
root: thumbnailsDiv,
// The vertical root margin is set to 100% to also track thumbnails that
// are one standard finger swipe away.
rootMargin: '100% 0%',
});
}
/** /**
* @return {!Array<number>} The array of page numbers. * @return {!Array<number>} The array of page numbers.
* @private * @private
...@@ -45,6 +78,13 @@ export class ViewerThumbnailBarElement extends PolymerElement { ...@@ -45,6 +78,13 @@ export class ViewerThumbnailBarElement extends PolymerElement {
isActivePage_(page) { isActivePage_(page) {
return this.activePage === page; return this.activePage === page;
} }
/** @private */
onDomChange_() {
this.shadowRoot.querySelectorAll('viewer-thumbnail').forEach(thumbnail => {
this.intersectionObserver_.observe(thumbnail);
});
}
} }
customElements.define(ViewerThumbnailBarElement.is, ViewerThumbnailBarElement); customElements.define(ViewerThumbnailBarElement.is, ViewerThumbnailBarElement);
<style> <style>
:host {
display: block;
}
#thumbnail { #thumbnail {
/** /**
* TODO(crbug.com/652400): Remove div size and change inactive background * TODO(crbug.com/652400): Remove div size and change inactive background
...@@ -10,7 +14,6 @@ ...@@ -10,7 +14,6 @@
margin-bottom: 12px; margin-bottom: 12px;
margin-inline-end: auto; margin-inline-end: auto;
margin-inline-start: auto; margin-inline-start: auto;
margin-top: 24px;
width: 108px; width: 108px;
} }
......
...@@ -59,6 +59,75 @@ const tests = [ ...@@ -59,6 +59,75 @@ const tests = [
} }
}); });
}, },
function testTriggerPaint() {
// Create a viewer-thumbnail element to get the standard height.
document.body.innerHTML = '';
const sizerThumbnail = document.createElement('viewer-thumbnail');
document.body.appendChild(sizerThumbnail);
// Add 24 to cover padding between thumbnails.
const thumbnailBarHeight = sizerThumbnail.offsetHeight + 24;
// Clear HTML for just the thumbnail bar.
const testDocLength = 4;
const thumbnailBar = createThumbnailBar();
thumbnailBar.docLength = testDocLength;
// Set the height to one thumbnail. One thumbnail should be visible and
// another should be hidden by intersecting the observer.
thumbnailBar.style.height = `${thumbnailBarHeight}px`;
thumbnailBar.style.display = 'block';
flush();
const thumbnails =
/** @type {!NodeList<!ViewerThumbnailElement>} */ (
thumbnailBar.shadowRoot.querySelectorAll('viewer-thumbnail'));
/**
* @param {!ViewerThumbnailElement} thumbnail
* @return {!Promise}
*/
function paintThumbnailToPromise(thumbnail) {
return new Promise(resolve => {
const eventType = 'paint-thumbnail';
thumbnailBar.addEventListener(eventType, function f(e) {
if (e.detail === thumbnail) {
thumbnailBar.removeEventListener(eventType, f);
resolve(e);
}
});
});
}
const whenRequestedPaintingFirst = [
paintThumbnailToPromise(thumbnails[0]),
paintThumbnailToPromise(thumbnails[1]),
];
testAsync(async () => {
await Promise.all(whenRequestedPaintingFirst);
// Only two thumbnails should be pending.
for (let i = 0; i < thumbnails.length; i++) {
chrome.test.assertEq(i < 2, thumbnails[i].hasAttribute('pending'));
}
// Test that scrolling to the bottom triggers 'paint-thumbnail' events for
// the remaining thumbnails.
const whenRequestedPaintingLast = [
paintThumbnailToPromise(thumbnails[2]),
paintThumbnailToPromise(thumbnails[3]),
];
thumbnailBar.shadowRoot.querySelector('#thumbnails').scrollTop =
2 * thumbnailBarHeight;
await Promise.all(whenRequestedPaintingLast);
for (const thumbnail of thumbnails) {
chrome.test.assertTrue(thumbnail.hasAttribute('pending'));
}
});
}
]; ];
chrome.test.runTests(tests); chrome.test.runTests(tests);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment