@file-viewer/pptx 2.1.16 → 2.1.17
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/styles.d.ts +1 -1
- package/dist/styles.js +2 -0
- package/dist/viewer.d.ts +29 -0
- package/dist/viewer.js +342 -14
- package/package.json +2 -2
package/dist/styles.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const pptxViewerCss = "\n.flyfish-pptx-scale-box{position:relative;box-sizing:border-box;max-width:100%;margin:0 auto;min-width:0}\n.flyfish-pptx-content{position:absolute;top:0;left:0;box-sizing:border-box;max-width:none;min-width:0;transform-origin:top left;will-change:transform}\n.flyfish-pptx-content[data-render-state=\"loading\"]{opacity:.82}\n.flyfish-pptx-content .slide{background:#fff;box-shadow:0 18px 36px rgba(18,35,52,.12)}\n.flyfish-pptx-thumbnail{display:block;box-sizing:border-box;width:min(960px,100%);height:auto;margin:0 auto 28px;border-radius:12px;background:#fff;box-shadow:0 18px 36px rgba(18,35,52,.14)}\n\n.slide{position:relative;border:0;border-radius:0;overflow:hidden;margin-bottom:50px;margin-left:auto;margin-right:auto;z-index:100}\n.slide div.block{position:absolute;top:0;left:0;width:100%;line-height:1}\n.slide div.content{display:flex;flex-direction:column}\n.slide div.diagram-content{display:flex;flex-direction:column}\n.slide div.content-rtl{display:flex;flex-direction:column;direction:rtl}\n.slide .pregraph-rtl{direction:rtl}\n.slide .pregraph-ltr{direction:ltr}\n.slide .pregraph-inherit{direction:inherit}\n.slide .slide-prgrph{width:100%}\n.slide .line-break-br::before{content:\"\\A\";white-space:pre}\n.slide div.v-up{justify-content:flex-start}\n.slide div.v-mid{justify-content:center}\n.slide div.v-down{justify-content:flex-end}\n.slide div.h-left{justify-content:flex-start;align-items:flex-start;text-align:left}\n.slide div.h-left-rtl{justify-content:flex-end;align-items:flex-end;text-align:left}\n.slide div.h-mid{justify-content:center;align-items:center;text-align:center}\n.slide div.h-right{justify-content:flex-end;align-items:flex-end;text-align:right}\n.slide div.h-right-rtl{justify-content:flex-start;align-items:flex-start;text-align:right}\n.slide div.h-just,.slide div.h-dist{text-align:justify}\n.slide div.up-left{justify-content:flex-start;align-items:flex-start;text-align:left}\n.slide div.up-center{justify-content:flex-start;align-items:center}\n.slide div.up-right{justify-content:flex-start;align-items:flex-end}\n.slide div.center-left{justify-content:center;align-items:flex-start;text-align:left}\n.slide div.center-center{justify-content:center;align-items:center}\n.slide div.center-right{justify-content:center;align-items:flex-end}\n.slide div.down-left{justify-content:flex-end;align-items:flex-start;text-align:left}\n.slide div.down-center{justify-content:flex-end;align-items:center}\n.slide div.down-right{justify-content:flex-end;align-items:flex-end}\n.slide li.slide{margin:10px 0;font-size:18px}\n.slide table{position:absolute}\n.slide svg.drawing{position:absolute;overflow:visible}\n\n.flyfish-pptx-content > .slide:last-of-type{margin-bottom:0}\n";
|
|
1
|
+
export declare const pptxViewerCss = "\n.flyfish-pptx-scale-box{position:relative;box-sizing:border-box;max-width:100%;margin:0 auto;min-width:0}\n.flyfish-pptx-content{position:absolute;top:0;left:0;box-sizing:border-box;max-width:none;min-width:0;transform-origin:top left;will-change:transform}\n.flyfish-pptx-content[data-render-state=\"loading\"]{opacity:.82}\n.flyfish-pptx-slide-slot{display:flow-root;box-sizing:border-box;width:100%;min-width:0}\n.flyfish-pptx-content .slide{background:#fff;box-shadow:0 18px 36px rgba(18,35,52,.12)}\n.flyfish-pptx-thumbnail{display:block;box-sizing:border-box;width:min(960px,100%);height:auto;margin:0 auto 28px;border-radius:12px;background:#fff;box-shadow:0 18px 36px rgba(18,35,52,.14)}\n\n.slide{position:relative;border:0;border-radius:0;overflow:hidden;margin-bottom:50px;margin-left:auto;margin-right:auto;z-index:100}\n.slide div.block{position:absolute;top:0;left:0;width:100%;line-height:1}\n.slide div.content{display:flex;flex-direction:column}\n.slide div.diagram-content{display:flex;flex-direction:column}\n.slide div.content-rtl{display:flex;flex-direction:column;direction:rtl}\n.slide .pregraph-rtl{direction:rtl}\n.slide .pregraph-ltr{direction:ltr}\n.slide .pregraph-inherit{direction:inherit}\n.slide .slide-prgrph{width:100%}\n.slide .line-break-br::before{content:\"\\A\";white-space:pre}\n.slide div.v-up{justify-content:flex-start}\n.slide div.v-mid{justify-content:center}\n.slide div.v-down{justify-content:flex-end}\n.slide div.h-left{justify-content:flex-start;align-items:flex-start;text-align:left}\n.slide div.h-left-rtl{justify-content:flex-end;align-items:flex-end;text-align:left}\n.slide div.h-mid{justify-content:center;align-items:center;text-align:center}\n.slide div.h-right{justify-content:flex-end;align-items:flex-end;text-align:right}\n.slide div.h-right-rtl{justify-content:flex-start;align-items:flex-start;text-align:right}\n.slide div.h-just,.slide div.h-dist{text-align:justify}\n.slide div.up-left{justify-content:flex-start;align-items:flex-start;text-align:left}\n.slide div.up-center{justify-content:flex-start;align-items:center}\n.slide div.up-right{justify-content:flex-start;align-items:flex-end}\n.slide div.center-left{justify-content:center;align-items:flex-start;text-align:left}\n.slide div.center-center{justify-content:center;align-items:center}\n.slide div.center-right{justify-content:center;align-items:flex-end}\n.slide div.down-left{justify-content:flex-end;align-items:flex-start;text-align:left}\n.slide div.down-center{justify-content:flex-end;align-items:center}\n.slide div.down-right{justify-content:flex-end;align-items:flex-end}\n.slide li.slide{margin:10px 0;font-size:18px}\n.slide table{position:absolute}\n.slide svg.drawing{position:absolute;overflow:visible}\n\n.flyfish-pptx-content > .slide:last-of-type{margin-bottom:0}\n.flyfish-pptx-slide-slot:last-of-type > .slide{margin-bottom:0}\n";
|
|
2
2
|
export declare const ensurePptxViewerStyles: (documentRef: Document) => void;
|
package/dist/styles.js
CHANGED
|
@@ -35,10 +35,12 @@ export const pptxViewerCss = `
|
|
|
35
35
|
.flyfish-pptx-scale-box{position:relative;box-sizing:border-box;max-width:100%;margin:0 auto;min-width:0}
|
|
36
36
|
.flyfish-pptx-content{position:absolute;top:0;left:0;box-sizing:border-box;max-width:none;min-width:0;transform-origin:top left;will-change:transform}
|
|
37
37
|
.flyfish-pptx-content[data-render-state="loading"]{opacity:.82}
|
|
38
|
+
.flyfish-pptx-slide-slot{display:flow-root;box-sizing:border-box;width:100%;min-width:0}
|
|
38
39
|
.flyfish-pptx-content .slide{background:#fff;box-shadow:0 18px 36px rgba(18,35,52,.12)}
|
|
39
40
|
.flyfish-pptx-thumbnail{display:block;box-sizing:border-box;width:min(960px,100%);height:auto;margin:0 auto 28px;border-radius:12px;background:#fff;box-shadow:0 18px 36px rgba(18,35,52,.14)}
|
|
40
41
|
${legacyPptxCss}
|
|
41
42
|
.flyfish-pptx-content > .slide:last-of-type{margin-bottom:0}
|
|
43
|
+
.flyfish-pptx-slide-slot:last-of-type > .slide{margin-bottom:0}
|
|
42
44
|
`;
|
|
43
45
|
const PPTX_STYLE_ID = 'flyfish-pptx-native-style';
|
|
44
46
|
export const ensurePptxViewerStyles = (documentRef) => {
|
package/dist/viewer.d.ts
CHANGED
|
@@ -13,8 +13,15 @@ export declare class PptxViewer {
|
|
|
13
13
|
private userZoomPercent;
|
|
14
14
|
private currentZoomPercent;
|
|
15
15
|
private thumbnailElement;
|
|
16
|
+
private slideSize;
|
|
17
|
+
private slideRecords;
|
|
18
|
+
private slideWindowTarget;
|
|
19
|
+
private slideWindowListeners;
|
|
20
|
+
private slideWindowFrame;
|
|
21
|
+
private charts;
|
|
16
22
|
private disposed;
|
|
17
23
|
private completed;
|
|
24
|
+
private readonly handleSlideWindowChange;
|
|
18
25
|
private constructor();
|
|
19
26
|
get zoomPercent(): number;
|
|
20
27
|
open(): Promise<void>;
|
|
@@ -25,9 +32,31 @@ export declare class PptxViewer {
|
|
|
25
32
|
private appendGlobalCss;
|
|
26
33
|
private showThumbnail;
|
|
27
34
|
private clearThumbnail;
|
|
35
|
+
private shouldWindowSlides;
|
|
36
|
+
private getSlideWindowOptions;
|
|
37
|
+
private getEstimatedSlideHeight;
|
|
38
|
+
private appendWindowedSlide;
|
|
39
|
+
private createWindowedSlideRecord;
|
|
40
|
+
private renderSlideRecord;
|
|
41
|
+
private unmountSlideRecord;
|
|
42
|
+
private updateMeasuredSlideHeight;
|
|
43
|
+
private syncWindowedPlaceholderHeights;
|
|
44
|
+
private scheduleSlideWindowUpdate;
|
|
45
|
+
private updateSlideWindow;
|
|
46
|
+
private getWindowedSlideIndexes;
|
|
47
|
+
private getDistanceFromViewport;
|
|
48
|
+
private getSlideViewport;
|
|
49
|
+
private attachSlideWindowListeners;
|
|
50
|
+
private addSlideWindowListener;
|
|
51
|
+
private detachSlideWindowListeners;
|
|
52
|
+
private findSlideWindowTarget;
|
|
53
|
+
private postProcessRenderedContent;
|
|
54
|
+
private postProcessSlideRecord;
|
|
28
55
|
private complete;
|
|
29
56
|
private fail;
|
|
30
57
|
private attachResizeObserver;
|
|
31
58
|
private scheduleResize;
|
|
32
59
|
private resize;
|
|
60
|
+
private getMountedSlideElements;
|
|
61
|
+
private isSlideElement;
|
|
33
62
|
}
|
package/dist/viewer.js
CHANGED
|
@@ -25,6 +25,21 @@ const appendHtml = (container, html) => {
|
|
|
25
25
|
container.append(template.content);
|
|
26
26
|
return nodes[0] || null;
|
|
27
27
|
};
|
|
28
|
+
const DEFAULT_INITIAL_SLIDES = 3;
|
|
29
|
+
const DEFAULT_BATCH_SIZE = 4;
|
|
30
|
+
const DEFAULT_OVERSCAN_VIEWPORTS = 1.5;
|
|
31
|
+
const DEFAULT_SLIDE_HEIGHT = 540;
|
|
32
|
+
const DEFAULT_SLIDE_GAP = 50;
|
|
33
|
+
const toPositiveInteger = (value, fallback, min = 1, max = Number.MAX_SAFE_INTEGER) => {
|
|
34
|
+
const numeric = typeof value === 'number' && Number.isFinite(value)
|
|
35
|
+
? Math.floor(value)
|
|
36
|
+
: fallback;
|
|
37
|
+
return clamp(numeric, min, max);
|
|
38
|
+
};
|
|
39
|
+
const toPositiveNumber = (value, fallback, min = 0, max = Number.MAX_SAFE_INTEGER) => {
|
|
40
|
+
const numeric = typeof value === 'number' && Number.isFinite(value) ? value : fallback;
|
|
41
|
+
return clamp(numeric, min, max);
|
|
42
|
+
};
|
|
28
43
|
export class PptxViewer {
|
|
29
44
|
static async open(buffer, target, options = {}) {
|
|
30
45
|
const viewer = new PptxViewer(buffer, target, options);
|
|
@@ -39,8 +54,15 @@ export class PptxViewer {
|
|
|
39
54
|
this.userZoomPercent = 100;
|
|
40
55
|
this.currentZoomPercent = 100;
|
|
41
56
|
this.thumbnailElement = null;
|
|
57
|
+
this.slideSize = null;
|
|
58
|
+
this.slideRecords = [];
|
|
59
|
+
this.slideWindowTarget = null;
|
|
60
|
+
this.slideWindowListeners = [];
|
|
61
|
+
this.slideWindowFrame = 0;
|
|
62
|
+
this.charts = null;
|
|
42
63
|
this.disposed = false;
|
|
43
64
|
this.completed = false;
|
|
65
|
+
this.handleSlideWindowChange = () => this.scheduleSlideWindowUpdate();
|
|
44
66
|
this.buffer = buffer;
|
|
45
67
|
this.target = target;
|
|
46
68
|
this.options = options;
|
|
@@ -62,6 +84,7 @@ export class PptxViewer {
|
|
|
62
84
|
ensurePptxViewerStyles(this.target.ownerDocument || document);
|
|
63
85
|
this.target.replaceChildren(this.scaleBox);
|
|
64
86
|
this.attachResizeObserver();
|
|
87
|
+
this.attachSlideWindowListeners();
|
|
65
88
|
this.startWorker();
|
|
66
89
|
}
|
|
67
90
|
async setZoom(percent) {
|
|
@@ -70,7 +93,7 @@ export class PptxViewer {
|
|
|
70
93
|
this.scheduleResize();
|
|
71
94
|
}
|
|
72
95
|
destroy() {
|
|
73
|
-
var _a, _b, _c;
|
|
96
|
+
var _a, _b, _c, _d;
|
|
74
97
|
this.disposed = true;
|
|
75
98
|
(_a = this.worker) === null || _a === void 0 ? void 0 : _a.terminate();
|
|
76
99
|
this.worker = null;
|
|
@@ -79,12 +102,20 @@ export class PptxViewer {
|
|
|
79
102
|
if (this.resizeFrame) {
|
|
80
103
|
(_c = this.target.ownerDocument.defaultView) === null || _c === void 0 ? void 0 : _c.cancelAnimationFrame(this.resizeFrame);
|
|
81
104
|
}
|
|
105
|
+
if (this.slideWindowFrame) {
|
|
106
|
+
(_d = this.target.ownerDocument.defaultView) === null || _d === void 0 ? void 0 : _d.cancelAnimationFrame(this.slideWindowFrame);
|
|
107
|
+
}
|
|
108
|
+
this.detachSlideWindowListeners();
|
|
82
109
|
this.target.replaceChildren();
|
|
83
110
|
}
|
|
84
111
|
startWorker() {
|
|
85
112
|
var _a;
|
|
86
113
|
(_a = this.worker) === null || _a === void 0 ? void 0 : _a.terminate();
|
|
87
114
|
this.completed = false;
|
|
115
|
+
this.charts = null;
|
|
116
|
+
this.slideSize = null;
|
|
117
|
+
this.slideRecords = [];
|
|
118
|
+
this.content.replaceChildren();
|
|
88
119
|
this.content.dataset.renderState = 'loading';
|
|
89
120
|
this.worker = createPptxWorker(this.options);
|
|
90
121
|
this.worker.addEventListener('message', event => this.processMessage(event.data));
|
|
@@ -104,9 +135,14 @@ export class PptxViewer {
|
|
|
104
135
|
switch (message.type) {
|
|
105
136
|
case 'slide': {
|
|
106
137
|
this.clearThumbnail();
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
138
|
+
if (this.shouldWindowSlides()) {
|
|
139
|
+
this.appendWindowedSlide(String(message.data || ''), Number(message.slide_num || 0));
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
const element = appendHtml(this.content, String(message.data || ''));
|
|
143
|
+
this.scheduleResize();
|
|
144
|
+
(_b = (_a = this.options).onSlideRendered) === null || _b === void 0 ? void 0 : _b.call(_a, Number(message.slide_num || 0), element);
|
|
145
|
+
}
|
|
110
146
|
break;
|
|
111
147
|
}
|
|
112
148
|
case 'pptx-thumb':
|
|
@@ -114,6 +150,8 @@ export class PptxViewer {
|
|
|
114
150
|
(_d = (_c = this.options).onThumbnail) === null || _d === void 0 ? void 0 : _d.call(_c, String(message.data || ''));
|
|
115
151
|
break;
|
|
116
152
|
case 'slideSize':
|
|
153
|
+
this.slideSize = (message.data || {});
|
|
154
|
+
this.syncWindowedPlaceholderHeights();
|
|
117
155
|
(_f = (_e = this.options).onSlideSize) === null || _f === void 0 ? void 0 : _f.call(_e, (message.data || {}));
|
|
118
156
|
break;
|
|
119
157
|
case 'globalCSS':
|
|
@@ -160,17 +198,283 @@ export class PptxViewer {
|
|
|
160
198
|
(_a = this.thumbnailElement) === null || _a === void 0 ? void 0 : _a.remove();
|
|
161
199
|
this.thumbnailElement = null;
|
|
162
200
|
}
|
|
201
|
+
shouldWindowSlides() {
|
|
202
|
+
var _a;
|
|
203
|
+
return Boolean(this.options.lazySlides || ((_a = this.options.listOptions) === null || _a === void 0 ? void 0 : _a.windowed));
|
|
204
|
+
}
|
|
205
|
+
getSlideWindowOptions() {
|
|
206
|
+
const listOptions = this.options.listOptions || {};
|
|
207
|
+
return {
|
|
208
|
+
initialSlides: toPositiveInteger(listOptions.initialSlides, DEFAULT_INITIAL_SLIDES, 1, 20),
|
|
209
|
+
batchSize: toPositiveInteger(listOptions.batchSize, DEFAULT_BATCH_SIZE, 1, 20),
|
|
210
|
+
overscanViewport: toPositiveNumber(listOptions.overscanViewport, DEFAULT_OVERSCAN_VIEWPORTS, 0.25, 6),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
getEstimatedSlideHeight() {
|
|
214
|
+
var _a, _b;
|
|
215
|
+
const sizeHeight = Number((_a = this.slideSize) === null || _a === void 0 ? void 0 : _a.height);
|
|
216
|
+
const measuredHeight = (_b = this.slideRecords.find(record => record.estimatedHeight > 0)) === null || _b === void 0 ? void 0 : _b.estimatedHeight;
|
|
217
|
+
return Math.ceil((Number.isFinite(sizeHeight) && sizeHeight > 0
|
|
218
|
+
? sizeHeight + DEFAULT_SLIDE_GAP
|
|
219
|
+
: measuredHeight || DEFAULT_SLIDE_HEIGHT + DEFAULT_SLIDE_GAP));
|
|
220
|
+
}
|
|
221
|
+
appendWindowedSlide(html, slideNumber) {
|
|
222
|
+
const record = this.createWindowedSlideRecord(html, slideNumber || this.slideRecords.length + 1);
|
|
223
|
+
this.slideRecords.push(record);
|
|
224
|
+
this.content.append(record.slot);
|
|
225
|
+
if (this.slideRecords.length <= this.getSlideWindowOptions().initialSlides) {
|
|
226
|
+
this.renderSlideRecord(record);
|
|
227
|
+
}
|
|
228
|
+
this.scheduleResize();
|
|
229
|
+
this.scheduleSlideWindowUpdate();
|
|
230
|
+
}
|
|
231
|
+
createWindowedSlideRecord(html, slideNumber) {
|
|
232
|
+
const slot = this.target.ownerDocument.createElement('div');
|
|
233
|
+
const estimatedHeight = this.getEstimatedSlideHeight();
|
|
234
|
+
slot.className = 'flyfish-pptx-slide-slot';
|
|
235
|
+
slot.dataset.slideNumber = String(slideNumber);
|
|
236
|
+
slot.style.minHeight = `${estimatedHeight}px`;
|
|
237
|
+
return {
|
|
238
|
+
slideNumber,
|
|
239
|
+
html,
|
|
240
|
+
slot,
|
|
241
|
+
element: null,
|
|
242
|
+
estimatedHeight,
|
|
243
|
+
rendered: false,
|
|
244
|
+
notified: false,
|
|
245
|
+
postProcessed: false,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
renderSlideRecord(record) {
|
|
249
|
+
var _a, _b;
|
|
250
|
+
if (record.rendered || this.disposed) {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
record.slot.replaceChildren();
|
|
254
|
+
record.element = appendHtml(record.slot, record.html);
|
|
255
|
+
record.rendered = true;
|
|
256
|
+
record.postProcessed = false;
|
|
257
|
+
this.updateMeasuredSlideHeight(record);
|
|
258
|
+
if (!record.notified) {
|
|
259
|
+
record.notified = true;
|
|
260
|
+
(_b = (_a = this.options).onSlideRendered) === null || _b === void 0 ? void 0 : _b.call(_a, record.slideNumber, record.element);
|
|
261
|
+
}
|
|
262
|
+
if (this.completed) {
|
|
263
|
+
void this.postProcessSlideRecord(record).finally(() => this.scheduleResize());
|
|
264
|
+
}
|
|
265
|
+
this.scheduleResize();
|
|
266
|
+
}
|
|
267
|
+
unmountSlideRecord(record) {
|
|
268
|
+
if (!record.rendered) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
this.updateMeasuredSlideHeight(record);
|
|
272
|
+
record.slot.replaceChildren();
|
|
273
|
+
record.element = null;
|
|
274
|
+
record.rendered = false;
|
|
275
|
+
record.postProcessed = false;
|
|
276
|
+
}
|
|
277
|
+
updateMeasuredSlideHeight(record) {
|
|
278
|
+
var _a;
|
|
279
|
+
const HTMLElementCtor = ((_a = this.target.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.HTMLElement) || HTMLElement;
|
|
280
|
+
if (!(record.element instanceof HTMLElementCtor)) {
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const view = this.target.ownerDocument.defaultView || window;
|
|
284
|
+
const computed = view.getComputedStyle(record.element);
|
|
285
|
+
const marginTop = parseFloat(computed.marginTop) || 0;
|
|
286
|
+
const marginBottom = parseFloat(computed.marginBottom) || 0;
|
|
287
|
+
const measuredHeight = Math.ceil(record.element.offsetHeight + marginTop + marginBottom);
|
|
288
|
+
const nextHeight = Math.max(measuredHeight, record.estimatedHeight, 1);
|
|
289
|
+
record.estimatedHeight = nextHeight;
|
|
290
|
+
record.slot.style.minHeight = `${nextHeight}px`;
|
|
291
|
+
}
|
|
292
|
+
syncWindowedPlaceholderHeights() {
|
|
293
|
+
if (!this.shouldWindowSlides() || !this.slideRecords.length) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
const estimatedHeight = this.getEstimatedSlideHeight();
|
|
297
|
+
for (const record of this.slideRecords) {
|
|
298
|
+
if (!record.rendered && record.estimatedHeight < estimatedHeight) {
|
|
299
|
+
record.estimatedHeight = estimatedHeight;
|
|
300
|
+
record.slot.style.minHeight = `${estimatedHeight}px`;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
this.scheduleResize();
|
|
304
|
+
}
|
|
305
|
+
scheduleSlideWindowUpdate() {
|
|
306
|
+
if (!this.shouldWindowSlides() || this.disposed) {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const view = this.target.ownerDocument.defaultView || window;
|
|
310
|
+
if (this.slideWindowFrame) {
|
|
311
|
+
view.cancelAnimationFrame(this.slideWindowFrame);
|
|
312
|
+
}
|
|
313
|
+
this.slideWindowFrame = view.requestAnimationFrame(() => this.updateSlideWindow());
|
|
314
|
+
}
|
|
315
|
+
updateSlideWindow() {
|
|
316
|
+
this.slideWindowFrame = 0;
|
|
317
|
+
if (!this.shouldWindowSlides() || !this.slideRecords.length || this.disposed) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const windowOptions = this.getSlideWindowOptions();
|
|
321
|
+
const indexesToRender = this.getWindowedSlideIndexes(windowOptions);
|
|
322
|
+
let changed = false;
|
|
323
|
+
this.slideRecords.forEach((record, index) => {
|
|
324
|
+
if (indexesToRender.has(index)) {
|
|
325
|
+
const wasRendered = record.rendered;
|
|
326
|
+
this.renderSlideRecord(record);
|
|
327
|
+
changed || (changed = !wasRendered);
|
|
328
|
+
}
|
|
329
|
+
else if (record.rendered) {
|
|
330
|
+
this.unmountSlideRecord(record);
|
|
331
|
+
changed = true;
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
if (changed) {
|
|
335
|
+
this.scheduleResize();
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
getWindowedSlideIndexes(windowOptions) {
|
|
339
|
+
const viewport = this.getSlideViewport();
|
|
340
|
+
const maxMountedSlides = Math.max(windowOptions.initialSlides, windowOptions.initialSlides + windowOptions.batchSize * 4, 12);
|
|
341
|
+
const selected = new Set();
|
|
342
|
+
for (let index = 0; index < Math.min(windowOptions.initialSlides, this.slideRecords.length); index += 1) {
|
|
343
|
+
selected.add(index);
|
|
344
|
+
}
|
|
345
|
+
const candidates = this.slideRecords
|
|
346
|
+
.map((record, index) => ({
|
|
347
|
+
index,
|
|
348
|
+
distance: this.getDistanceFromViewport(record, viewport, windowOptions.overscanViewport),
|
|
349
|
+
}))
|
|
350
|
+
.filter(candidate => candidate.distance !== Number.POSITIVE_INFINITY)
|
|
351
|
+
.sort((a, b) => a.distance - b.distance || a.index - b.index);
|
|
352
|
+
const closestFallback = candidates[0];
|
|
353
|
+
for (const candidate of candidates) {
|
|
354
|
+
if (candidate.distance > 0 && selected.size >= windowOptions.initialSlides) {
|
|
355
|
+
continue;
|
|
356
|
+
}
|
|
357
|
+
selected.add(candidate.index);
|
|
358
|
+
}
|
|
359
|
+
if (closestFallback) {
|
|
360
|
+
selected.add(closestFallback.index);
|
|
361
|
+
}
|
|
362
|
+
if (selected.size <= maxMountedSlides) {
|
|
363
|
+
return selected;
|
|
364
|
+
}
|
|
365
|
+
const capped = new Set();
|
|
366
|
+
for (let index = 0; index < Math.min(windowOptions.initialSlides, this.slideRecords.length); index += 1) {
|
|
367
|
+
capped.add(index);
|
|
368
|
+
}
|
|
369
|
+
for (const candidate of candidates) {
|
|
370
|
+
if (capped.size >= maxMountedSlides) {
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
capped.add(candidate.index);
|
|
374
|
+
}
|
|
375
|
+
return capped;
|
|
376
|
+
}
|
|
377
|
+
getDistanceFromViewport(record, viewport, overscanViewport) {
|
|
378
|
+
const rect = record.slot.getBoundingClientRect();
|
|
379
|
+
const overscan = viewport.height * overscanViewport;
|
|
380
|
+
const top = viewport.top - overscan;
|
|
381
|
+
const bottom = viewport.bottom + overscan;
|
|
382
|
+
if (rect.bottom >= top && rect.top <= bottom) {
|
|
383
|
+
return 0;
|
|
384
|
+
}
|
|
385
|
+
if (rect.bottom < top) {
|
|
386
|
+
return top - rect.bottom;
|
|
387
|
+
}
|
|
388
|
+
if (rect.top > bottom) {
|
|
389
|
+
return rect.top - bottom;
|
|
390
|
+
}
|
|
391
|
+
return Number.POSITIVE_INFINITY;
|
|
392
|
+
}
|
|
393
|
+
getSlideViewport() {
|
|
394
|
+
const view = this.target.ownerDocument.defaultView || window;
|
|
395
|
+
const HTMLElementCtor = view.HTMLElement;
|
|
396
|
+
if (this.slideWindowTarget instanceof HTMLElementCtor) {
|
|
397
|
+
const rect = this.slideWindowTarget.getBoundingClientRect();
|
|
398
|
+
const height = Math.max(1, rect.height || this.slideWindowTarget.clientHeight || view.innerHeight || 1);
|
|
399
|
+
return {
|
|
400
|
+
top: rect.top,
|
|
401
|
+
bottom: rect.top + height,
|
|
402
|
+
height,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
const height = Math.max(1, view.innerHeight || this.target.ownerDocument.documentElement.clientHeight || DEFAULT_SLIDE_HEIGHT);
|
|
406
|
+
return {
|
|
407
|
+
top: 0,
|
|
408
|
+
bottom: height,
|
|
409
|
+
height,
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
attachSlideWindowListeners() {
|
|
413
|
+
if (!this.shouldWindowSlides()) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
this.detachSlideWindowListeners();
|
|
417
|
+
const view = this.target.ownerDocument.defaultView || window;
|
|
418
|
+
this.slideWindowTarget = this.findSlideWindowTarget();
|
|
419
|
+
this.addSlideWindowListener(view, 'scroll');
|
|
420
|
+
this.addSlideWindowListener(view, 'resize');
|
|
421
|
+
if (this.slideWindowTarget && this.slideWindowTarget !== view) {
|
|
422
|
+
this.addSlideWindowListener(this.slideWindowTarget, 'scroll');
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
addSlideWindowListener(target, type) {
|
|
426
|
+
target.addEventListener(type, this.handleSlideWindowChange, { passive: true });
|
|
427
|
+
this.slideWindowListeners.push({ target, type, listener: this.handleSlideWindowChange });
|
|
428
|
+
}
|
|
429
|
+
detachSlideWindowListeners() {
|
|
430
|
+
for (const { target, type, listener } of this.slideWindowListeners) {
|
|
431
|
+
target.removeEventListener(type, listener);
|
|
432
|
+
}
|
|
433
|
+
this.slideWindowListeners = [];
|
|
434
|
+
this.slideWindowTarget = null;
|
|
435
|
+
}
|
|
436
|
+
findSlideWindowTarget() {
|
|
437
|
+
const view = this.target.ownerDocument.defaultView || window;
|
|
438
|
+
let element = this.target.parentElement;
|
|
439
|
+
while (element && element !== this.target.ownerDocument.body && element !== this.target.ownerDocument.documentElement) {
|
|
440
|
+
const style = view.getComputedStyle(element);
|
|
441
|
+
if (/(auto|scroll|overlay)/.test(`${style.overflowY} ${style.overflow}`)) {
|
|
442
|
+
return element;
|
|
443
|
+
}
|
|
444
|
+
element = element.parentElement;
|
|
445
|
+
}
|
|
446
|
+
return view;
|
|
447
|
+
}
|
|
448
|
+
async postProcessRenderedContent(charts) {
|
|
449
|
+
if (!this.shouldWindowSlides()) {
|
|
450
|
+
await renderPptxPostProcessing(charts, this.content);
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
await Promise.all(this.slideRecords
|
|
454
|
+
.filter(record => record.rendered)
|
|
455
|
+
.map(record => this.postProcessSlideRecord(record)));
|
|
456
|
+
}
|
|
457
|
+
async postProcessSlideRecord(record) {
|
|
458
|
+
if (!record.rendered || record.postProcessed || this.disposed) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
await renderPptxPostProcessing(this.charts, record.slot);
|
|
462
|
+
record.postProcessed = true;
|
|
463
|
+
this.updateMeasuredSlideHeight(record);
|
|
464
|
+
}
|
|
163
465
|
async complete(charts) {
|
|
164
466
|
var _a, _b, _c;
|
|
165
467
|
if (this.disposed || this.completed) {
|
|
166
468
|
return;
|
|
167
469
|
}
|
|
168
470
|
this.completed = true;
|
|
471
|
+
this.charts = charts;
|
|
169
472
|
this.content.dataset.renderState = 'ready';
|
|
170
473
|
(_a = this.worker) === null || _a === void 0 ? void 0 : _a.terminate();
|
|
171
474
|
this.worker = null;
|
|
475
|
+
this.scheduleSlideWindowUpdate();
|
|
172
476
|
this.scheduleResize();
|
|
173
|
-
await
|
|
477
|
+
await this.postProcessRenderedContent(charts);
|
|
174
478
|
this.scheduleResize();
|
|
175
479
|
(_c = (_b = this.options).onRenderComplete) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
176
480
|
}
|
|
@@ -189,7 +493,10 @@ export class PptxViewer {
|
|
|
189
493
|
if (typeof ResizeObserver === 'undefined') {
|
|
190
494
|
return;
|
|
191
495
|
}
|
|
192
|
-
this.resizeObserver = new ResizeObserver(() =>
|
|
496
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
497
|
+
this.scheduleResize();
|
|
498
|
+
this.scheduleSlideWindowUpdate();
|
|
499
|
+
});
|
|
193
500
|
this.resizeObserver.observe(this.target);
|
|
194
501
|
if (this.target.parentElement) {
|
|
195
502
|
this.resizeObserver.observe(this.target.parentElement);
|
|
@@ -204,14 +511,10 @@ export class PptxViewer {
|
|
|
204
511
|
}
|
|
205
512
|
resize() {
|
|
206
513
|
var _a, _b;
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
if (!slides.length) {
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
const slideWidth = Math.max(...slides.map(slide => slide.offsetWidth), 0);
|
|
514
|
+
const slides = this.getMountedSlideElements();
|
|
515
|
+
const sizeWidth = Number((_a = this.slideSize) === null || _a === void 0 ? void 0 : _a.width);
|
|
516
|
+
const fallbackWidth = Number.isFinite(sizeWidth) && sizeWidth > 0 ? sizeWidth : 0;
|
|
517
|
+
const slideWidth = Math.max(...slides.map(slide => slide.offsetWidth), fallbackWidth);
|
|
215
518
|
if (!slideWidth) {
|
|
216
519
|
return;
|
|
217
520
|
}
|
|
@@ -227,4 +530,29 @@ export class PptxViewer {
|
|
|
227
530
|
this.scaleBox.style.height = `${Math.ceil(this.content.scrollHeight * effectiveScale)}px`;
|
|
228
531
|
this.scaleBox.style.minHeight = '';
|
|
229
532
|
}
|
|
533
|
+
getMountedSlideElements() {
|
|
534
|
+
var _a;
|
|
535
|
+
const HTMLElementCtor = ((_a = this.target.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.HTMLElement) || HTMLElement;
|
|
536
|
+
const slides = [];
|
|
537
|
+
for (const child of Array.from(this.content.children)) {
|
|
538
|
+
if (!(child instanceof HTMLElementCtor)) {
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
if (this.isSlideElement(child)) {
|
|
542
|
+
slides.push(child);
|
|
543
|
+
continue;
|
|
544
|
+
}
|
|
545
|
+
if (!child.classList.contains('flyfish-pptx-slide-slot')) {
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
const firstChild = child.firstElementChild;
|
|
549
|
+
if (firstChild instanceof HTMLElementCtor && this.isSlideElement(firstChild)) {
|
|
550
|
+
slides.push(firstChild);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
return slides;
|
|
554
|
+
}
|
|
555
|
+
isSlideElement(element) {
|
|
556
|
+
return element.classList.contains('slide') || element.tagName === 'SECTION';
|
|
557
|
+
}
|
|
230
558
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@file-viewer/pptx",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.17",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Native PPTX renderer extracted from Flyfish File Viewer",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"funding": {
|
|
35
35
|
"type": "individual",
|
|
36
|
-
"url": "https://dev.flyfish.group/
|
|
36
|
+
"url": "https://dev.flyfish.group/donate?source=npm"
|
|
37
37
|
},
|
|
38
38
|
"main": "./dist/index.js",
|
|
39
39
|
"module": "./dist/index.js",
|