bloom-player 2.8.10 → 2.9.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/{bloomPlayer.CR0hgNXu.js → bloomPlayer.GowEHU-u.js} +37 -37
- package/dist/bloomplayer.htm +1 -1
- package/package.json +6 -1
- package/src/dragActivityRuntime.ts +1320 -0
- package/src/event.ts +25 -0
- package/src/narration.ts +1333 -0
- package/src/scrolling.ts +452 -0
package/src/scrolling.ts
ADDED
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
import $ from "jquery";
|
|
2
|
+
import "jquery.nicescroll";
|
|
3
|
+
import { IsRunningOnBloomDesktop } from "./dragActivityRuntime";
|
|
4
|
+
|
|
5
|
+
export const kSelectorForPotentialNiceScrollElements =
|
|
6
|
+
".bloom-translationGroup:not(.bloom-imageDescription) .bloom-editable.bloom-visibility-code-on, " +
|
|
7
|
+
".scrollable"; // we added .scrollable for branding cases where the boilerplate text also needs to scroll
|
|
8
|
+
|
|
9
|
+
// Add a "nice" scrollbar to the page if the content overflows.
|
|
10
|
+
export function addScrollbarsToPage(
|
|
11
|
+
bloomPage: Element,
|
|
12
|
+
pointerEventHandler?: (e: PointerEvent) => void,
|
|
13
|
+
): void {
|
|
14
|
+
// Expected behavior for cover: "on the cover, which is has a very dynamic layout, we just don't do scrollbars"
|
|
15
|
+
if (bloomPage.classList.contains("cover")) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const isRunningOnBloomDesktop = IsRunningOnBloomDesktop(bloomPage);
|
|
19
|
+
|
|
20
|
+
// on a browser so obsolete that it doesn't have IntersectionObserver (e.g., IE or Safari before 12.2),
|
|
21
|
+
// we just won't get scrolling.
|
|
22
|
+
if ("IntersectionObserver" in window) {
|
|
23
|
+
// Attach overlaid scrollbar to all editables except textOverPictures (e.g. comics)
|
|
24
|
+
// Expected behavior for comic bubbles: "we want overflow to show, but not generate scroll bars"
|
|
25
|
+
let scrollBlocks: HTMLElement[] = [];
|
|
26
|
+
let countOfObserversExpectedToReport = 0;
|
|
27
|
+
let countOfObserversThatHaveReported = 0;
|
|
28
|
+
$(bloomPage)
|
|
29
|
+
.find(kSelectorForPotentialNiceScrollElements)
|
|
30
|
+
.each((index, elt) => {
|
|
31
|
+
// Process the blocks that are possibly overflowing.
|
|
32
|
+
// Blocks that are overflowing will be configured to use niceScroll
|
|
33
|
+
// so the user can scroll and see everything. That is costly, because
|
|
34
|
+
// niceScroll leaks event listeners every time it is called. So we don't
|
|
35
|
+
// want to use it any more than we need to. (Is this true?) Also, niceScroll
|
|
36
|
+
// somehow fails to work when our vertical alignment classes are applied;
|
|
37
|
+
// probably something to do with the bloom-editables being display:flex
|
|
38
|
+
// to achieve vertical positioning. We can safely remove those classes
|
|
39
|
+
// if the block is overflowing, because there's no excess white space
|
|
40
|
+
// to distribute.
|
|
41
|
+
// Note: there are complications Bloom desktop handles in determining
|
|
42
|
+
// accurately whether a block is overflowing. We don't handle those here.
|
|
43
|
+
// If it is close enough to overflow to get a scroll bar, it's close
|
|
44
|
+
// enough not to care whether extra white space is at the top, bottom,
|
|
45
|
+
// or split (hence we can safely remove classes used for that).
|
|
46
|
+
// And we'll risk sometimes adding niceScroll when we could (just)
|
|
47
|
+
// have done without it. Using the same code in Bloom Desktop and bloom-player
|
|
48
|
+
// ensures consistent scrollbar behavior between the two.
|
|
49
|
+
const firstChild = elt.firstElementChild;
|
|
50
|
+
const lastChild = elt.lastElementChild;
|
|
51
|
+
if (!firstChild || !lastChild) {
|
|
52
|
+
// no children, can't be overflowing
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// We need to know the scale of the page, because nicescroll doesn't handle
|
|
57
|
+
// scaling when it comes to the padding that we add to the top and left of
|
|
58
|
+
// the translationGroup element. See BL-13796.
|
|
59
|
+
let scale = 1;
|
|
60
|
+
// bloom-player approach to setting the scale
|
|
61
|
+
const scaleStyle = document.querySelector(
|
|
62
|
+
"style#scale-style-sheet",
|
|
63
|
+
);
|
|
64
|
+
if (scaleStyle) {
|
|
65
|
+
const match = scaleStyle.innerHTML.match(
|
|
66
|
+
/transform:[a-z0-9, ()]* scale\((\d+(\.\d+)?)\)/,
|
|
67
|
+
);
|
|
68
|
+
if (match) {
|
|
69
|
+
scale = parseFloat(match[1]);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
// Bloom Desktop approach to setting the scale
|
|
73
|
+
const scaleContainer = elt.closest(
|
|
74
|
+
"#page-scaling-container",
|
|
75
|
+
) as HTMLElement;
|
|
76
|
+
if (scaleContainer) {
|
|
77
|
+
const scaleValue = scaleContainer.style.transform;
|
|
78
|
+
if (scaleValue && scaleValue.startsWith("scale(")) {
|
|
79
|
+
scale = parseFloat(
|
|
80
|
+
scaleValue.substring(6, scaleValue.length - 1),
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// nicescroll doesn't provide a way to adjust the height of the scrollbar
|
|
86
|
+
// ("rail"). Adjusting the height of the thumb ("cursor") is counterproductive
|
|
87
|
+
// if the scrollbar height doesn't change, so we don't try to adjust that
|
|
88
|
+
// aspect of the thumb.
|
|
89
|
+
const { topAdjust, leftAdjust, thumbWidth } =
|
|
90
|
+
ComputeNiceScrollOffsets(scale, elt as HTMLElement);
|
|
91
|
+
|
|
92
|
+
// We don't really want continuous observation, but this is an elegant
|
|
93
|
+
// way to find out whether each child is entirely contained within its
|
|
94
|
+
// parent. Unlike computations involving coordinates, we don't have to
|
|
95
|
+
// worry about whether borders, margins, and padding are included in
|
|
96
|
+
// various measurements. We do need to check the first as well as the
|
|
97
|
+
// last child, because if text is aligned bottom, any overflow will be
|
|
98
|
+
// at the top.
|
|
99
|
+
const observer = new IntersectionObserver(
|
|
100
|
+
(entries, ob) => {
|
|
101
|
+
// called more-or-less immediately for each child, but after the
|
|
102
|
+
// loop creates them all.
|
|
103
|
+
entries.forEach((entry) => {
|
|
104
|
+
countOfObserversThatHaveReported++;
|
|
105
|
+
ob.unobserve(entry.target); // don't want to keep getting them, or leak observers
|
|
106
|
+
const isBubble = !!entry.target.closest(
|
|
107
|
+
".bloom-textOverPicture",
|
|
108
|
+
);
|
|
109
|
+
// In bloom desktop preview, we set width to 200% and then scale down by 50%.
|
|
110
|
+
// This can lead to intersection ratios very slightly less than 1, probably due
|
|
111
|
+
// to pixel rounding of some sort, when in fact the content fits comfortably.
|
|
112
|
+
// For example, in one case we got a boundingClientRect 72.433 high
|
|
113
|
+
// and an intersectionRect 72.416, for a ratio of 0.9998.
|
|
114
|
+
// If a block is 1000 pixels high and really overflowing by 1 pixel, the ratio
|
|
115
|
+
// will be 0.999. I think it's safe to take anything closer to 1 than that as
|
|
116
|
+
// 'not overflowing'.
|
|
117
|
+
let overflowing = entry.intersectionRatio < 0.999;
|
|
118
|
+
|
|
119
|
+
if (overflowing && isBubble) {
|
|
120
|
+
// We want to be less aggressive about putting scroll bars on bubbles.
|
|
121
|
+
// Most of the time, a bubble is very carefully sized to just fit the
|
|
122
|
+
// text. But the intersection observer wants it to fit a certain amount
|
|
123
|
+
// of white space as well. We want a scroll bar if it's overflowing
|
|
124
|
+
// really badly for some reason, but that's much more the exception
|
|
125
|
+
// than the rule, so better a little clipping when the bubble is badly
|
|
126
|
+
// sized than a scroll bar that isn't needed in one that is just right.
|
|
127
|
+
// Example: a bubble which appears to fit perfectly, 3 lines high:
|
|
128
|
+
// its clientHeight is 72; containing bloom-editable's is 59;
|
|
129
|
+
// lineHeight is 24px. IntersectionRatio computes to 59/72,
|
|
130
|
+
// which makes the 'overflow' 13. A ratio of 0.5 as we originally
|
|
131
|
+
// proposed would give us a scroll bar we don't want.
|
|
132
|
+
let maxBubbleOverflowLineFraction = 0.6;
|
|
133
|
+
if (
|
|
134
|
+
entry.target !=
|
|
135
|
+
entry.target.parentElement
|
|
136
|
+
?.firstElementChild ||
|
|
137
|
+
entry.target !=
|
|
138
|
+
entry.target.parentElement!
|
|
139
|
+
.lastElementChild
|
|
140
|
+
) {
|
|
141
|
+
// Bubbles are center-aligned vertically. If this is not the only
|
|
142
|
+
// child,the first and last will overflow above and below by about the
|
|
143
|
+
// same amount. So we're only really looking at half the overflow on this para,
|
|
144
|
+
// and should reduce the threshold.
|
|
145
|
+
maxBubbleOverflowLineFraction /= 2;
|
|
146
|
+
}
|
|
147
|
+
const overflow =
|
|
148
|
+
(1 - entry.intersectionRatio) *
|
|
149
|
+
entry.target.clientHeight;
|
|
150
|
+
const lineHeightPx = window.getComputedStyle(
|
|
151
|
+
entry.target,
|
|
152
|
+
).lineHeight;
|
|
153
|
+
const lineHeight = parseFloat(
|
|
154
|
+
// remove the trailing "px"
|
|
155
|
+
lineHeightPx.substring(
|
|
156
|
+
0,
|
|
157
|
+
lineHeightPx.length - 2,
|
|
158
|
+
),
|
|
159
|
+
);
|
|
160
|
+
overflowing =
|
|
161
|
+
overflow >
|
|
162
|
+
lineHeight * maxBubbleOverflowLineFraction;
|
|
163
|
+
}
|
|
164
|
+
if (
|
|
165
|
+
overflowing &&
|
|
166
|
+
scrollBlocks.indexOf(
|
|
167
|
+
entry.target.parentElement!,
|
|
168
|
+
) < 0
|
|
169
|
+
) {
|
|
170
|
+
scrollBlocks.push(entry.target.parentElement!);
|
|
171
|
+
// remove classes incompatible with niceScroll
|
|
172
|
+
const group =
|
|
173
|
+
entry.target.parentElement!.parentElement!;
|
|
174
|
+
if (
|
|
175
|
+
group.classList.contains(
|
|
176
|
+
"bloom-vertical-align-center",
|
|
177
|
+
)
|
|
178
|
+
) {
|
|
179
|
+
group.classList.remove(
|
|
180
|
+
"bloom-vertical-align-center",
|
|
181
|
+
);
|
|
182
|
+
if (isRunningOnBloomDesktop)
|
|
183
|
+
group.classList.add(
|
|
184
|
+
"bloom-vertical-align-center-removed",
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
if (
|
|
188
|
+
group.classList.contains(
|
|
189
|
+
"bloom-vertical-align-bottom",
|
|
190
|
+
)
|
|
191
|
+
) {
|
|
192
|
+
group.classList.remove(
|
|
193
|
+
"bloom-vertical-align-bottom",
|
|
194
|
+
);
|
|
195
|
+
if (isRunningOnBloomDesktop)
|
|
196
|
+
group.classList.add(
|
|
197
|
+
"bloom-vertical-align-bottom-removed",
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
if (isBubble) {
|
|
201
|
+
// This is a way of forcing it not to be display-flex, which doesn't
|
|
202
|
+
// work with the nice-scroll-bar library we're using.
|
|
203
|
+
// That library messes with the element style, so it seemed safer
|
|
204
|
+
// not to do that myself.
|
|
205
|
+
entry.target.parentElement!.classList.add(
|
|
206
|
+
"scrolling-bubble",
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (
|
|
211
|
+
countOfObserversThatHaveReported ===
|
|
212
|
+
countOfObserversExpectedToReport
|
|
213
|
+
) {
|
|
214
|
+
// configure nicescroll...ideally only once for all of them
|
|
215
|
+
$(scrollBlocks).niceScroll({
|
|
216
|
+
autohidemode: false,
|
|
217
|
+
railoffset: {
|
|
218
|
+
top: -topAdjust,
|
|
219
|
+
left: -leftAdjust,
|
|
220
|
+
},
|
|
221
|
+
cursorwidth: thumbWidth,
|
|
222
|
+
cursorcolor: "#000000",
|
|
223
|
+
cursoropacitymax: 0.1,
|
|
224
|
+
cursorborderradius: thumbWidth, // Make the corner more rounded than the 5px default.
|
|
225
|
+
});
|
|
226
|
+
setupSpecialMouseTrackingForNiceScroll(
|
|
227
|
+
bloomPage,
|
|
228
|
+
pointerEventHandler,
|
|
229
|
+
);
|
|
230
|
+
scrollBlocks = []; // Just in case it's possible to get callbacks before we created them all.
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
},
|
|
234
|
+
{ root: elt },
|
|
235
|
+
);
|
|
236
|
+
countOfObserversExpectedToReport++;
|
|
237
|
+
observer.observe(firstChild);
|
|
238
|
+
if (firstChild !== lastChild) {
|
|
239
|
+
countOfObserversExpectedToReport++;
|
|
240
|
+
observer.observe(lastChild);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// This method is copied from the nicescroll source code, albeit with some renamings and
|
|
247
|
+
// getting rid of jquery as much as possible. This is how nicescroll determines the parent
|
|
248
|
+
// element that should have the inserted scrollbar elements. If nothing is found by this
|
|
249
|
+
// method, nicescroll uses the body element. Since the nicescroll release hasn't been updated
|
|
250
|
+
// since 2017, I feel safe in copying this method here in January 2025.
|
|
251
|
+
function getNiceScrollParent(elt: HTMLElement): HTMLElement | null {
|
|
252
|
+
var parentElt =
|
|
253
|
+
elt && elt.parentNode ? (elt.parentNode as HTMLElement) : null;
|
|
254
|
+
while (
|
|
255
|
+
parentElt &&
|
|
256
|
+
parentElt.nodeType === Node.ELEMENT_NODE &&
|
|
257
|
+
!/^BODY|HTML/.test(parentElt.nodeName)
|
|
258
|
+
) {
|
|
259
|
+
const computed = window.getComputedStyle(parentElt);
|
|
260
|
+
const position = computed.getPropertyValue("position");
|
|
261
|
+
if (/fixed|absolute/.test(position)) return parentElt;
|
|
262
|
+
const ov =
|
|
263
|
+
computed.getPropertyValue("overflow-y") ||
|
|
264
|
+
computed.getPropertyValue("overflow-x") ||
|
|
265
|
+
computed.getPropertyValue("overflow") ||
|
|
266
|
+
"";
|
|
267
|
+
if (
|
|
268
|
+
/scroll|auto/.test(ov) &&
|
|
269
|
+
parentElt.clientHeight != parentElt.scrollHeight
|
|
270
|
+
)
|
|
271
|
+
return parentElt;
|
|
272
|
+
if (($(parentElt).getNiceScroll() as any).length > 0) return parentElt;
|
|
273
|
+
parentElt = parentElt.parentNode
|
|
274
|
+
? (parentElt.parentNode as HTMLElement)
|
|
275
|
+
: null;
|
|
276
|
+
}
|
|
277
|
+
return null;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// nicescroll doesn't properly scale the padding at the top and left of the
|
|
281
|
+
// scrollable area of the languageGroup divs when the page is scaled. This
|
|
282
|
+
// method computes offset values to correct for this. See BL-13796.
|
|
283
|
+
// nicescroll also doesn't scale at all when nicescroll cannot find a scrollable
|
|
284
|
+
// area containing the element under the scaling div. See BL-14112.
|
|
285
|
+
function ComputeNiceScrollOffsets(
|
|
286
|
+
scale: number,
|
|
287
|
+
elt: HTMLElement,
|
|
288
|
+
): { topAdjust: number; leftAdjust: number; thumbWidth: string } {
|
|
289
|
+
let topAdjust = 0;
|
|
290
|
+
let leftAdjust = 0;
|
|
291
|
+
let thumbWidth = "12px"; // nicescroll calls the thumb a "cursor", but it's really a thumb
|
|
292
|
+
if (scale !== 1) {
|
|
293
|
+
const translationGroupDiv = elt.parentElement;
|
|
294
|
+
if (
|
|
295
|
+
!translationGroupDiv ||
|
|
296
|
+
!translationGroupDiv.classList.contains("bloom-translationGroup")
|
|
297
|
+
) {
|
|
298
|
+
// We don't know how to deal with this case, so we'll just return the default values.
|
|
299
|
+
return { topAdjust, leftAdjust, thumbWidth };
|
|
300
|
+
}
|
|
301
|
+
const whereToPutTheScrollbars = getNiceScrollParent(elt);
|
|
302
|
+
if (whereToPutTheScrollbars) {
|
|
303
|
+
// The nicescroll elements are added somewhere in the DOM that is presumably inside
|
|
304
|
+
// the element that sets the scaling.
|
|
305
|
+
const compStyles = window.getComputedStyle(translationGroupDiv);
|
|
306
|
+
const topPadding =
|
|
307
|
+
compStyles.getPropertyValue("padding-top") || "0";
|
|
308
|
+
const leftPadding =
|
|
309
|
+
compStyles.getPropertyValue("padding-left") || "0";
|
|
310
|
+
topAdjust = parseFloat(topPadding) * (scale - 1);
|
|
311
|
+
leftAdjust = parseFloat(leftPadding) * (scale - 1);
|
|
312
|
+
} else {
|
|
313
|
+
// The nicescroll elements are added directly under the body element, which is presumably
|
|
314
|
+
// outside the element that sets the scaling. We need to adjust for the scaling of the
|
|
315
|
+
// scrollbar position and size ourselves. See BL-14112.
|
|
316
|
+
const splitPageComponentInner = translationGroupDiv.parentElement;
|
|
317
|
+
if (!splitPageComponentInner) {
|
|
318
|
+
// This should never happen, but if it does, we'll just return the default values.
|
|
319
|
+
return { topAdjust, leftAdjust, thumbWidth };
|
|
320
|
+
}
|
|
321
|
+
// This seems to apply only to text-only pages which don't have any additional padding
|
|
322
|
+
// to worry about: only the basic page dimensions given by the splitPageComponentInner
|
|
323
|
+
// element.
|
|
324
|
+
thumbWidth = `${12 * scale}px`;
|
|
325
|
+
const top = splitPageComponentInner?.offsetTop;
|
|
326
|
+
const right =
|
|
327
|
+
splitPageComponentInner.offsetLeft +
|
|
328
|
+
splitPageComponentInner.offsetWidth;
|
|
329
|
+
topAdjust = -(top * (scale - 1));
|
|
330
|
+
leftAdjust = -(right * (scale - 1));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return { topAdjust, leftAdjust, thumbWidth };
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export function setupSpecialMouseTrackingForNiceScroll(
|
|
337
|
+
bloomPage: Element,
|
|
338
|
+
pointerEventHandler?: (e: PointerEvent) => void,
|
|
339
|
+
) {
|
|
340
|
+
bloomPage.removeEventListener("pointerdown", listenForPointerDown); // only want one!
|
|
341
|
+
bloomPage.addEventListener("pointerdown", listenForPointerDown);
|
|
342
|
+
if (!pointerEventHandler) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
// The purpose of this is to prevent Swiper causing the page to be moved or
|
|
346
|
+
// flicked when the user is trying to scroll on the page. See BL-14079.
|
|
347
|
+
for (const eventName of ["pointermove", "pointerup"]) {
|
|
348
|
+
bloomPage.ownerDocument.body.addEventListener(
|
|
349
|
+
eventName,
|
|
350
|
+
pointerEventHandler,
|
|
351
|
+
{
|
|
352
|
+
capture: true,
|
|
353
|
+
},
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// nicescroll doesn't properly scale the padding at the top and left of the
|
|
359
|
+
// scrollable area of the languageGroup divs when the page is scaled. This
|
|
360
|
+
// method sets offset values to correct for this. It is called whenever the
|
|
361
|
+
// entire window resizes, which also scales the page before this is called.
|
|
362
|
+
// See BL-13796.
|
|
363
|
+
export function fixNiceScrollOffsets(page: HTMLElement, scale: number) {
|
|
364
|
+
page.querySelectorAll(kSelectorForPotentialNiceScrollElements).forEach(
|
|
365
|
+
(group) => {
|
|
366
|
+
// The type definition is not correct for getNiceScroll; we expect it to return an array.
|
|
367
|
+
const groupNiceScroll = $(group).getNiceScroll() as any;
|
|
368
|
+
if (groupNiceScroll && groupNiceScroll.length > 0) {
|
|
369
|
+
let { topAdjust, leftAdjust, thumbWidth } =
|
|
370
|
+
ComputeNiceScrollOffsets(scale, group as HTMLElement);
|
|
371
|
+
groupNiceScroll[0].opt.railoffset.top = -topAdjust;
|
|
372
|
+
groupNiceScroll[0].opt.railoffset.left = -leftAdjust;
|
|
373
|
+
groupNiceScroll[0].opt.cursorwidth = thumbWidth;
|
|
374
|
+
groupNiceScroll[0].resize();
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// If the mouse down is in the thumb of a NiceScroll, we don't want to get a click
|
|
381
|
+
// event later even if the mouse up is outside that element. Also, we want the
|
|
382
|
+
// scrolling to follow the mouse movement even if the mouse cursor leaves the thumb
|
|
383
|
+
// before the mouse button is released.
|
|
384
|
+
function listenForPointerDown(ev: PointerEvent) {
|
|
385
|
+
if (
|
|
386
|
+
ev.target instanceof HTMLDivElement &&
|
|
387
|
+
(ev.target as HTMLDivElement).classList.contains("nicescroll-cursors")
|
|
388
|
+
) {
|
|
389
|
+
(ev.target as HTMLDivElement).setPointerCapture(ev.pointerId);
|
|
390
|
+
if (ev.pointerType === "mouse") {
|
|
391
|
+
// Investigation shows that Swiper uses pointer event handlers and NiceScroll
|
|
392
|
+
// uses mouse event handlers, so stopping the propagation of pointer events
|
|
393
|
+
// doesn't effect the scrolling, but does stop the swiping. See BL-14079.
|
|
394
|
+
// Pointer capture affects mouse events as well as pointer events.
|
|
395
|
+
ev.stopPropagation();
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export function cleanupNiceScroll() {
|
|
401
|
+
// Doing this cleanup is unfortunate overhead, but niceScrolls stick around too much,
|
|
402
|
+
// including when the page divs they are on are removed because the page is not the
|
|
403
|
+
// current page. This leads to performance issues, including the scrollbar getting darker
|
|
404
|
+
// and darker as the nicescroll elements build up in the HTML. This may also be the source
|
|
405
|
+
// of the event listener leaks that was mentioned in an earlier comment.
|
|
406
|
+
$("div.bloom-page")[0]
|
|
407
|
+
?.querySelectorAll(kSelectorForPotentialNiceScrollElements)
|
|
408
|
+
.forEach((group) => {
|
|
409
|
+
// The "as" cast is crucial here for this code to work. For some reason,
|
|
410
|
+
// the type returned by getNiceScroll() is not interpreted correctly and
|
|
411
|
+
// the code silently fails to work, with length always being 0.
|
|
412
|
+
// (bloom-player uses "as any" in this context, but "as JQuery" seems to
|
|
413
|
+
// work as well and doesn't trigger an eslint warning.)
|
|
414
|
+
const groupNiceScroll = $(
|
|
415
|
+
group,
|
|
416
|
+
).getNiceScroll() as unknown as JQuery;
|
|
417
|
+
if (groupNiceScroll && groupNiceScroll.length > 0) {
|
|
418
|
+
groupNiceScroll.remove();
|
|
419
|
+
}
|
|
420
|
+
// Remove classes added to make the niceScroll work, and restore
|
|
421
|
+
// classes that were removed to make the niceScroll work.
|
|
422
|
+
if (group.classList.contains("scrolling-bubble")) {
|
|
423
|
+
group.classList.remove("scrolling-bubble");
|
|
424
|
+
}
|
|
425
|
+
const groupParent = group.parentElement;
|
|
426
|
+
if (!groupParent) return; // this should never happen, but just in case
|
|
427
|
+
if (
|
|
428
|
+
groupParent.classList.contains(
|
|
429
|
+
"bloom-vertical-align-center-removed",
|
|
430
|
+
)
|
|
431
|
+
) {
|
|
432
|
+
groupParent.classList.remove(
|
|
433
|
+
"bloom-vertical-align-center-removed",
|
|
434
|
+
);
|
|
435
|
+
groupParent.classList.add("bloom-vertical-align-center");
|
|
436
|
+
}
|
|
437
|
+
if (
|
|
438
|
+
groupParent.classList.contains(
|
|
439
|
+
"bloom-vertical-align-bottom-removed",
|
|
440
|
+
)
|
|
441
|
+
) {
|
|
442
|
+
groupParent.classList.remove(
|
|
443
|
+
"bloom-vertical-align-bottom-removed",
|
|
444
|
+
);
|
|
445
|
+
groupParent.classList.add("bloom-vertical-align-bottom");
|
|
446
|
+
}
|
|
447
|
+
// Remove more debris left by niceScroll. See BL-14052.
|
|
448
|
+
(group as HTMLElement).style.overflow = "";
|
|
449
|
+
(group as HTMLElement).style.outline = "";
|
|
450
|
+
(group as HTMLElement).style.width = "";
|
|
451
|
+
});
|
|
452
|
+
}
|