Skip to content

Commit 4bc9a49

Browse files
committed
Adds comments.
1 parent deee0a3 commit 4bc9a49

File tree

2 files changed

+38
-6
lines changed

2 files changed

+38
-6
lines changed

frontend_build/src/parse_bundle_plugin.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ var parseBundlePlugin = function(data, base_dir) {
9090
],
9191
};
9292

93+
// Calculate these paths here, so that we can export __publicPath as a variable in the webpack define plugin
9394
var publicPath, outputPath;
9495

9596
if (process.env.DEV_SERVER) {
@@ -121,6 +122,7 @@ var parseBundlePlugin = function(data, base_dir) {
121122
__events: JSON.stringify(data.events || {}),
122123
__once: JSON.stringify(data.once || {}),
123124
__version: JSON.stringify(data.version),
125+
// This is necessary to allow modules that use service workers to fetch their service worker code
124126
__publicPath: JSON.stringify(publicPath),
125127
}),
126128
new extract$trs(data.locale_data_folder, data.name),

kolibri/plugins/document_pdf_render/assets/src/views/index.vue

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,16 @@
5757
import { sessionTimeSpent } from 'kolibri.coreVue.vuex.getters';
5858
import { debounce } from 'lodash';
5959
60+
// Source from which PDFJS loads its service worker, this is based on the __publicPath
61+
// global that is defined in the Kolibri webpack pipeline, and the additional entry in the PDF renderer's
62+
// own webpack config
6063
PDFJSLib.PDFJS.workerSrc = `${__publicPath}pdfJSWorker-${__version}.js`;
6164
6265
// Number of pages before and after current visible to keep rendered
6366
const pageDisplayWindow = 1;
67+
// How often should we respond to changes in scrolling to render new pages?
6468
const renderDebounceTime = 300;
69+
// Minimum height of the PDF viewer in pixels
6570
const minViewerHeight = 400;
6671
6772
export default {
@@ -136,8 +141,9 @@
136141
// Get viewport, which contains directions to be passed into render function
137142
const viewport = pdfPage.getViewport(this.scale);
138143
139-
// put together the canvas element where page will be rendered
140-
const canvas = document.createElement('canvas');
144+
// create the canvas element where page will be rendered
145+
// we do this dynamically to avoid having many canvas elements simultaneously in the page
146+
const canvas = this.pdfPages[pageNum].canvas || document.createElement('canvas');
141147
142148
// define canvas and dummy blank page dimensions
143149
canvas.width = this.pageWidth = viewport.width;
@@ -151,6 +157,7 @@
151157
viewport,
152158
});
153159
160+
// Keep track of the canvas in case we need to manipulate it later
154161
this.pdfPages[pageNum].canvas = canvas;
155162
this.pdfPages[pageNum].renderTask = renderTask;
156163
this.pdfPages[pageNum].rendering = true;
@@ -162,8 +169,8 @@
162169
163170
renderTask.then(
164171
() => {
172+
// If this has been removed since the rendering started, then we should not proceed
165173
if (this.pdfPages[pageNum]) {
166-
this.pdfPages[pageNum].rendering = false;
167174
if (this.pdfPages[pageNum].canvas) {
168175
// Canvas has not been deleted in the interim
169176
this.pdfPages[pageNum].rendered = true;
@@ -174,8 +181,11 @@
174181
this.currentPageRendering = false;
175182
}
176183
}
184+
// Rendering has completed
185+
this.pdfPages[pageNum].rendering = false;
177186
}
178187
},
188+
// If the render task is cancelled, then it will reject the promise and end up here.
179189
() => {
180190
if (this.pdfPages[pageNum]) {
181191
this.pdfPages[pageNum].rendering = false;
@@ -187,15 +197,20 @@
187197
},
188198
showPage(pageNum) {
189199
if (pageNum <= this.totalPages && pageNum > 0) {
200+
// Only try to show pages that exist
190201
if (!this.pdfPages[pageNum]) {
191202
this.pdfPages[pageNum] = {};
192203
}
193204
if (
205+
// Do not try to show the page if it is already renderered,
206+
// already loading, or already rendering.
194207
!this.pdfPages[pageNum].rendered &&
195208
!this.pdfPages[pageNum].loading &&
196209
!this.pdfPages[pageNum].rendering
197210
) {
198211
this.pdfPages[pageNum].loading = true;
212+
// If we already have a reference to the PDFJS page object, then use it,
213+
// rather than refetching it.
199214
if (!this.pdfPages[pageNum].pdfPage) {
200215
this.pdfPages[pageNum].renderPromise = this.getPage(pageNum).then(this.startRender);
201216
} else {
@@ -206,27 +221,33 @@
206221
},
207222
hidePage(pageNum) {
208223
if (pageNum <= this.totalPages && pageNum > 0) {
224+
// Only try to hide possibly existing pages.
209225
if (!this.pdfPages[pageNum]) {
210-
// No page rendered, so do nothing
226+
// No page to render, so do nothing
211227
return;
212228
}
213229
const pdfPage = this.pdfPages[pageNum];
214230
if (pdfPage.rendered) {
215231
pdfPage.rendered = false;
232+
// Already rendered, just remove canvas from DOM.
216233
if (pdfPage.canvas) {
217234
pdfPage.canvas.remove();
218235
}
219236
} else if (pdfPage.loading) {
220-
// Currently loading, cancel the task
237+
// Otherwise, currently loading - let it finish the render promise,
238+
// where the page is still being fetched
239+
// then cancel the resulting renderTask.
221240
const renderTask = pdfPage.renderTask;
222241
pdfPage.renderPromise.then(() => {
223242
renderTask && renderTask.cancel();
224243
});
225244
} else if (pdfPage.rendering) {
226-
// Currently rendering, cancel the task
245+
// Currently rendering, cancel the task directly
227246
pdfPage.renderTask && pdfPage.renderTask.cancel();
228247
}
248+
// Clean everything up (destroys the pdf page object).
229249
pdfPage.pdfPage && pdfPage.pdfPage.cleanup();
250+
// Delete the reference so that this page is now a blank slate.
230251
delete this.pdfPages[pageNum];
231252
}
232253
},
@@ -235,13 +256,17 @@
235256
},
236257
// debouncing so we're not de/re-render many pages unnecessarily
237258
checkPages: debounce(function() {
259+
// Calculate the position of the visible top and the bottom of the pdfContainer
238260
const top = this.$refs.pdfContainer.scrollTop;
239261
const bottom = top + this.$refs.pdfContainer.clientHeight;
262+
// Then work out which pages are visible to the user as a consequence
240263
const topPageNum = Math.ceil(top / this.pageHeight);
241264
const bottomPageNum = Math.ceil(bottom / this.pageHeight);
242265
243266
// Loop through all pages, show ones that are in the display window, hide ones that aren't
244267
for (let i = 1; i <= this.totalPages; i++) {
268+
// Hide pages that are less than 'pageDisplayWindow' lower than the top page number
269+
// or the same amount higher than the bottom page number
245270
if (i < topPageNum - pageDisplayWindow || i > bottomPageNum + pageDisplayWindow) {
246271
this.hidePage(i);
247272
} else {
@@ -253,6 +278,7 @@
253278
watch: {
254279
scrollPos: 'checkPages',
255280
scale(newScale, oldScale) {
281+
// Listen to changes in scale, as we have to rerender every visible page if it changes.
256282
const noChange = newScale === oldScale;
257283
const firstChange = oldScale === null;
258284
@@ -281,6 +307,7 @@
281307
};
282308
283309
this.prepComponentData = loadPdfPromise.then(pdfDocument => {
310+
// Get initial info from the loaded pdf document
284311
this.pdfDocument = pdfDocument;
285312
this.totalPages = pdfDocument.numPages;
286313
this.pdfPages = {};
@@ -302,6 +329,9 @@
302329
const initialViewport = firstPage.getViewport(this.scale);
303330
this.pageHeight = initialViewport.height;
304331
this.pageWidth = initialViewport.width;
332+
// Set the firstPage into the pdfPages object so that we do not refetch the page
333+
// from PDFJS when we do our initial render
334+
this.pdfPages[1] = firstPage;
305335
});
306336
});
307337
},

0 commit comments

Comments
 (0)