@file-viewer/pptx 2.2.9 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/presentation.d.ts +66 -0
- package/dist/presentation.js +360 -0
- package/dist/styles.js +18 -0
- package/dist/types.d.ts +4 -0
- package/dist/viewer.d.ts +32 -0
- package/dist/viewer.js +159 -9
- package/dist/worker/pptx.worker.js +1 -1
- package/dist/worker.js +12 -1
- package/package.json +2 -2
package/dist/viewer.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { renderPptxPostProcessing } from './chart.js';
|
|
2
2
|
import { resolvePptxEngineOptions, RECOMMENDED_ZIP_LIMITS } from './options.js';
|
|
3
|
+
import { PptxPresentation } from './presentation.js';
|
|
3
4
|
import { sanitizePptxCss, sanitizePptxMarkup } from './sanitize.js';
|
|
4
5
|
import { ensurePptxViewerStyles } from './styles.js';
|
|
5
6
|
import { createPptxWorker } from './worker.js';
|
|
@@ -96,6 +97,13 @@ export class PptxViewer {
|
|
|
96
97
|
this.previewThumbnailDataUrl = null;
|
|
97
98
|
this.slideSize = null;
|
|
98
99
|
this.slideRecords = [];
|
|
100
|
+
// Total slides received from the worker. The windowed path mirrors this in
|
|
101
|
+
// slideRecords, but the default (non-windowed) path appends slides straight
|
|
102
|
+
// into the content node without creating records, so the deck size has to be
|
|
103
|
+
// counted independently of the virtualization bookkeeping.
|
|
104
|
+
this.totalSlides = 0;
|
|
105
|
+
this.savedScroll = null;
|
|
106
|
+
this.pendingScrollRestore = null;
|
|
99
107
|
this.slideWindowTarget = null;
|
|
100
108
|
this.slideWindowListeners = [];
|
|
101
109
|
this.slideWindowFrame = 0;
|
|
@@ -104,6 +112,7 @@ export class PptxViewer {
|
|
|
104
112
|
this.mediaRecords = new Map();
|
|
105
113
|
this.disposed = false;
|
|
106
114
|
this.completed = false;
|
|
115
|
+
this.presentation = null;
|
|
107
116
|
this.handleSlideWindowChange = () => this.scheduleSlideWindowUpdate();
|
|
108
117
|
this.buffer = buffer;
|
|
109
118
|
this.target = target;
|
|
@@ -124,9 +133,111 @@ export class PptxViewer {
|
|
|
124
133
|
get thumbnailDataUrl() {
|
|
125
134
|
return this.previewThumbnailDataUrl;
|
|
126
135
|
}
|
|
136
|
+
get slideCount() {
|
|
137
|
+
return this.totalSlides;
|
|
138
|
+
}
|
|
139
|
+
get slideDimensions() {
|
|
140
|
+
var _a, _b;
|
|
141
|
+
const width = Number((_a = this.slideSize) === null || _a === void 0 ? void 0 : _a.width);
|
|
142
|
+
const height = Number((_b = this.slideSize) === null || _b === void 0 ? void 0 : _b.height);
|
|
143
|
+
return Number.isFinite(width) && width > 0 && Number.isFinite(height) && height > 0
|
|
144
|
+
? { width, height }
|
|
145
|
+
: null;
|
|
146
|
+
}
|
|
147
|
+
get presenting() {
|
|
148
|
+
var _a;
|
|
149
|
+
return Boolean((_a = this.presentation) === null || _a === void 0 ? void 0 : _a.active);
|
|
150
|
+
}
|
|
151
|
+
get presentationSlideNumber() {
|
|
152
|
+
var _a, _b;
|
|
153
|
+
return (_b = (_a = this.presentation) === null || _a === void 0 ? void 0 : _a.slideNumber) !== null && _b !== void 0 ? _b : 1;
|
|
154
|
+
}
|
|
155
|
+
get styleRoot() {
|
|
156
|
+
var _a;
|
|
157
|
+
if (this.options.styleRoot) {
|
|
158
|
+
return this.options.styleRoot;
|
|
159
|
+
}
|
|
160
|
+
const documentRef = this.target.ownerDocument || document;
|
|
161
|
+
const root = this.target.getRootNode();
|
|
162
|
+
const ShadowRootCtor = (_a = documentRef.defaultView) === null || _a === void 0 ? void 0 : _a.ShadowRoot;
|
|
163
|
+
return ShadowRootCtor && root instanceof ShadowRootCtor
|
|
164
|
+
? root
|
|
165
|
+
: documentRef;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Where the slideshow overlay is mounted. It has to share a root with the injected slide styles,
|
|
169
|
+
* or the engine's scoped CSS stops applying once the slides move into the overlay.
|
|
170
|
+
*/
|
|
171
|
+
get presentationRoot() {
|
|
172
|
+
const documentRef = this.target.ownerDocument || document;
|
|
173
|
+
const styleRoot = this.styleRoot;
|
|
174
|
+
if (styleRoot !== documentRef) {
|
|
175
|
+
return styleRoot;
|
|
176
|
+
}
|
|
177
|
+
return documentRef.body || documentRef.documentElement;
|
|
178
|
+
}
|
|
179
|
+
/** Force a slide out of the virtualized window so the slideshow can show it immediately. */
|
|
180
|
+
ensureSlideRendered(slideNumber) {
|
|
181
|
+
const record = this.slideRecords.find(item => item.slideNumber === slideNumber);
|
|
182
|
+
if (!record) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
if (!record.rendered) {
|
|
186
|
+
this.renderSlideRecord(record);
|
|
187
|
+
}
|
|
188
|
+
return record.element;
|
|
189
|
+
}
|
|
190
|
+
refreshLayout() {
|
|
191
|
+
this.scheduleResize();
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Remember where the deck was scrolled before the slideshow moves the scale
|
|
195
|
+
* box into the overlay. Moving it collapses the scroller and clamps scrollTop
|
|
196
|
+
* to zero, so the position has to be captured up front and restored on exit.
|
|
197
|
+
*/
|
|
198
|
+
saveScrollPosition() {
|
|
199
|
+
const view = this.target.ownerDocument.defaultView || window;
|
|
200
|
+
const HTMLElementCtor = view.HTMLElement;
|
|
201
|
+
const scroller = this.slideWindowTarget || this.findSlideWindowTarget();
|
|
202
|
+
if (scroller instanceof HTMLElementCtor) {
|
|
203
|
+
this.savedScroll = { top: scroller.scrollTop, left: scroller.scrollLeft };
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
this.savedScroll = { top: view.scrollY, left: view.scrollX };
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
restoreScrollPosition() {
|
|
210
|
+
if (this.savedScroll) {
|
|
211
|
+
this.pendingScrollRestore = this.savedScroll;
|
|
212
|
+
this.savedScroll = null;
|
|
213
|
+
}
|
|
214
|
+
this.scheduleResize();
|
|
215
|
+
}
|
|
216
|
+
emitPresentationChange(state) {
|
|
217
|
+
var _a, _b;
|
|
218
|
+
(_b = (_a = this.options).onPresentationChange) === null || _b === void 0 ? void 0 : _b.call(_a, state);
|
|
219
|
+
}
|
|
220
|
+
async enterPresentation(slideNumber) {
|
|
221
|
+
if (this.disposed || this.totalSlides === 0) {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
this.presentation || (this.presentation = new PptxPresentation(this, this.options.presentationLabels, this.options.presentationFullscreen));
|
|
225
|
+
await this.presentation.enter(slideNumber);
|
|
226
|
+
}
|
|
227
|
+
exitPresentation() {
|
|
228
|
+
var _a;
|
|
229
|
+
(_a = this.presentation) === null || _a === void 0 ? void 0 : _a.exit();
|
|
230
|
+
}
|
|
231
|
+
async togglePresentation(slideNumber) {
|
|
232
|
+
if (this.presenting) {
|
|
233
|
+
this.exitPresentation();
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
await this.enterPresentation(slideNumber);
|
|
237
|
+
}
|
|
127
238
|
async open() {
|
|
128
239
|
ensureZipWithinLimits(this.buffer, this.options);
|
|
129
|
-
ensurePptxViewerStyles(this.target.ownerDocument || document, this.
|
|
240
|
+
ensurePptxViewerStyles(this.target.ownerDocument || document, this.styleRoot);
|
|
130
241
|
this.target.replaceChildren(this.scaleBox);
|
|
131
242
|
this.attachResizeObserver();
|
|
132
243
|
this.attachSlideWindowListeners();
|
|
@@ -138,20 +249,22 @@ export class PptxViewer {
|
|
|
138
249
|
this.scheduleResize();
|
|
139
250
|
}
|
|
140
251
|
destroy() {
|
|
141
|
-
var _a, _b, _c, _d;
|
|
252
|
+
var _a, _b, _c, _d, _e;
|
|
142
253
|
this.disposed = true;
|
|
254
|
+
(_a = this.presentation) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
255
|
+
this.presentation = null;
|
|
143
256
|
this.previewThumbnailDataUrl = null;
|
|
144
257
|
this.releaseCharts();
|
|
145
258
|
this.releaseMedia();
|
|
146
|
-
(
|
|
259
|
+
(_b = this.worker) === null || _b === void 0 ? void 0 : _b.terminate();
|
|
147
260
|
this.worker = null;
|
|
148
|
-
(
|
|
261
|
+
(_c = this.resizeObserver) === null || _c === void 0 ? void 0 : _c.disconnect();
|
|
149
262
|
this.resizeObserver = null;
|
|
150
263
|
if (this.resizeFrame) {
|
|
151
|
-
(
|
|
264
|
+
(_d = this.target.ownerDocument.defaultView) === null || _d === void 0 ? void 0 : _d.cancelAnimationFrame(this.resizeFrame);
|
|
152
265
|
}
|
|
153
266
|
if (this.slideWindowFrame) {
|
|
154
|
-
(
|
|
267
|
+
(_e = this.target.ownerDocument.defaultView) === null || _e === void 0 ? void 0 : _e.cancelAnimationFrame(this.slideWindowFrame);
|
|
155
268
|
}
|
|
156
269
|
this.detachSlideWindowListeners();
|
|
157
270
|
this.target.replaceChildren();
|
|
@@ -166,6 +279,7 @@ export class PptxViewer {
|
|
|
166
279
|
this.previewThumbnailDataUrl = null;
|
|
167
280
|
this.slideSize = null;
|
|
168
281
|
this.slideRecords = [];
|
|
282
|
+
this.totalSlides = 0;
|
|
169
283
|
this.content.replaceChildren();
|
|
170
284
|
this.content.dataset.renderState = 'loading';
|
|
171
285
|
try {
|
|
@@ -196,6 +310,7 @@ export class PptxViewer {
|
|
|
196
310
|
switch (message.type) {
|
|
197
311
|
case 'slide': {
|
|
198
312
|
this.clearThumbnail();
|
|
313
|
+
this.totalSlides += 1;
|
|
199
314
|
if (this.shouldWindowSlides()) {
|
|
200
315
|
this.appendWindowedSlide(String(message.data || ''), Number(message.slide_num || 0));
|
|
201
316
|
}
|
|
@@ -215,6 +330,7 @@ export class PptxViewer {
|
|
|
215
330
|
const error = message.data;
|
|
216
331
|
const html = buildSlideErrorHtml(slideNumber, error);
|
|
217
332
|
this.clearThumbnail();
|
|
333
|
+
this.totalSlides += 1;
|
|
218
334
|
if (this.shouldWindowSlides()) {
|
|
219
335
|
this.appendWindowedSlide(html, slideNumber);
|
|
220
336
|
}
|
|
@@ -420,6 +536,19 @@ export class PptxViewer {
|
|
|
420
536
|
}
|
|
421
537
|
const windowOptions = this.getSlideWindowOptions();
|
|
422
538
|
const indexesToRender = this.getWindowedSlideIndexes(windowOptions);
|
|
539
|
+
// While presenting, the active slide and its neighbour live inside the fixed
|
|
540
|
+
// overlay, outside the scroll-view geometry the windowing code measures. Keep
|
|
541
|
+
// them mounted so a resize cannot unmount the slide that is on screen.
|
|
542
|
+
const presentation = this.presentation;
|
|
543
|
+
if (presentation === null || presentation === void 0 ? void 0 : presentation.active) {
|
|
544
|
+
const activeIndex = this.slideRecords.findIndex(record => record.slideNumber === presentation.slideNumber);
|
|
545
|
+
if (activeIndex >= 0) {
|
|
546
|
+
indexesToRender.add(activeIndex);
|
|
547
|
+
if (activeIndex + 1 < this.slideRecords.length) {
|
|
548
|
+
indexesToRender.add(activeIndex + 1);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
423
552
|
let changed = false;
|
|
424
553
|
this.slideRecords.forEach((record, index) => {
|
|
425
554
|
if (indexesToRender.has(index)) {
|
|
@@ -748,15 +877,20 @@ export class PptxViewer {
|
|
|
748
877
|
this.resizeFrame = view.requestAnimationFrame(() => this.resize());
|
|
749
878
|
}
|
|
750
879
|
resize() {
|
|
751
|
-
var _a, _b;
|
|
880
|
+
var _a, _b, _c;
|
|
881
|
+
// While presenting, the slideshow owns the transform of the same nodes.
|
|
882
|
+
if ((_a = this.presentation) === null || _a === void 0 ? void 0 : _a.active) {
|
|
883
|
+
this.presentation.layout();
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
752
886
|
const slides = this.getMountedSlideElements();
|
|
753
|
-
const sizeWidth = Number((
|
|
887
|
+
const sizeWidth = Number((_b = this.slideSize) === null || _b === void 0 ? void 0 : _b.width);
|
|
754
888
|
const fallbackWidth = Number.isFinite(sizeWidth) && sizeWidth > 0 ? sizeWidth : 0;
|
|
755
889
|
const slideWidth = Math.max(...slides.map(slide => slide.offsetWidth), fallbackWidth);
|
|
756
890
|
if (!slideWidth) {
|
|
757
891
|
return;
|
|
758
892
|
}
|
|
759
|
-
const viewportWidth = this.target.clientWidth || ((
|
|
893
|
+
const viewportWidth = this.target.clientWidth || ((_c = this.target.parentElement) === null || _c === void 0 ? void 0 : _c.clientWidth) || slideWidth;
|
|
760
894
|
this.fitScale = this.options.fitMode === 'none'
|
|
761
895
|
? 1
|
|
762
896
|
: Math.min(1, viewportWidth / slideWidth);
|
|
@@ -767,6 +901,22 @@ export class PptxViewer {
|
|
|
767
901
|
this.scaleBox.style.width = `${Math.ceil(slideWidth * effectiveScale)}px`;
|
|
768
902
|
this.scaleBox.style.height = `${Math.ceil(this.content.scrollHeight * effectiveScale)}px`;
|
|
769
903
|
this.scaleBox.style.minHeight = '';
|
|
904
|
+
// The scale box height is recomputed above; only now can the saved scroll
|
|
905
|
+
// position be applied without the scroller clamping it back to zero.
|
|
906
|
+
if (this.pendingScrollRestore) {
|
|
907
|
+
const { top, left } = this.pendingScrollRestore;
|
|
908
|
+
this.pendingScrollRestore = null;
|
|
909
|
+
const view = this.target.ownerDocument.defaultView || window;
|
|
910
|
+
const HTMLElementCtor = view.HTMLElement;
|
|
911
|
+
const scroller = this.slideWindowTarget || this.findSlideWindowTarget();
|
|
912
|
+
if (scroller instanceof HTMLElementCtor) {
|
|
913
|
+
scroller.scrollTop = top;
|
|
914
|
+
scroller.scrollLeft = left;
|
|
915
|
+
}
|
|
916
|
+
else {
|
|
917
|
+
view.scrollTo(left, top);
|
|
918
|
+
}
|
|
919
|
+
}
|
|
770
920
|
}
|
|
771
921
|
getMountedSlideElements() {
|
|
772
922
|
var _a;
|