mirror of
https://github.com/SoPat712/Speeder.git
synced 2026-10-08 03:03:14 -04:00
fix(controller): preserve overlays in Firefox fullscreen
This commit is contained in:
3 files changed
+80
-7
No files matched your search
@@ -3144,6 +3144,12 @@ function setupControllerHostTracking(videoController, wrapper, mount) {
|
|||||||
resizeObserver.observe(geometryMount);
|
resizeObserver.observe(geometryMount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var mediaGeometryEvents = ["loadedmetadata", "play", "playing"];
|
||||||
|
mediaGeometryEvents.forEach(function(eventName) {
|
||||||
|
videoController.video.addEventListener(eventName, schedule, {
|
||||||
|
passive: true
|
||||||
|
});
|
||||||
|
});
|
||||||
win.addEventListener("resize", schedule, { passive: true });
|
win.addEventListener("resize", schedule, { passive: true });
|
||||||
doc.addEventListener("fullscreenchange", schedule, { passive: true });
|
doc.addEventListener("fullscreenchange", schedule, { passive: true });
|
||||||
geometryMount.addEventListener("scroll", schedule, { passive: true });
|
geometryMount.addEventListener("scroll", schedule, { passive: true });
|
||||||
@@ -3154,6 +3160,9 @@ function setupControllerHostTracking(videoController, wrapper, mount) {
|
|||||||
if (resizeObserver) resizeObserver.disconnect();
|
if (resizeObserver) resizeObserver.disconnect();
|
||||||
if (frameId !== null) win.cancelAnimationFrame(frameId);
|
if (frameId !== null) win.cancelAnimationFrame(frameId);
|
||||||
if (geometryRetryTimer !== null) win.clearTimeout(geometryRetryTimer);
|
if (geometryRetryTimer !== null) win.clearTimeout(geometryRetryTimer);
|
||||||
|
mediaGeometryEvents.forEach(function(eventName) {
|
||||||
|
videoController.video.removeEventListener(eventName, schedule);
|
||||||
|
});
|
||||||
win.removeEventListener("resize", schedule);
|
win.removeEventListener("resize", schedule);
|
||||||
doc.removeEventListener("fullscreenchange", schedule);
|
doc.removeEventListener("fullscreenchange", schedule);
|
||||||
geometryMount.removeEventListener("scroll", schedule);
|
geometryMount.removeEventListener("scroll", schedule);
|
||||||
@@ -3329,8 +3338,15 @@ function syncControllerFullscreenMount(videoController) {
|
|||||||
(fullscreenElement === video ||
|
(fullscreenElement === video ||
|
||||||
isComposedDescendant(video, fullscreenElement))
|
isComposedDescendant(video, fullscreenElement))
|
||||||
);
|
);
|
||||||
|
var normalGeometryMount = getControllerGeometryMount(targetMount);
|
||||||
|
var normalMountIsAlreadyFullscreenVisible = Boolean(
|
||||||
|
fullscreenElement &&
|
||||||
|
fullscreenElement !== video &&
|
||||||
|
normalGeometryMount &&
|
||||||
|
isComposedDescendant(normalGeometryMount, fullscreenElement)
|
||||||
|
);
|
||||||
|
|
||||||
if (ownsFullscreen) {
|
if (ownsFullscreen && !normalMountIsAlreadyFullscreenVisible) {
|
||||||
targetMount = getControllerMount(video, fullscreenElement);
|
targetMount = getControllerMount(video, fullscreenElement);
|
||||||
} else if (!fullscreenElement && (!targetMount || !targetMount.isConnected)) {
|
} else if (!fullscreenElement && (!targetMount || !targetMount.isConnected)) {
|
||||||
targetMount = getControllerMount(video);
|
targetMount = getControllerMount(video);
|
||||||
@@ -3950,6 +3966,9 @@ function defineVideoController() {
|
|||||||
const speed = this.video.playbackRate.toFixed(2);
|
const speed = this.video.playbackRate.toFixed(2);
|
||||||
var wrapper = doc.createElement("div");
|
var wrapper = doc.createElement("div");
|
||||||
wrapper.classList.add("vsc-controller");
|
wrapper.classList.add("vsc-controller");
|
||||||
|
// Keep the host out of player layout while its shadow stylesheet loads.
|
||||||
|
wrapper.style.position = "absolute";
|
||||||
|
wrapper.style.pointerEvents = "none";
|
||||||
if (!hasUsableMediaSource(this.video))
|
if (!hasUsableMediaSource(this.video))
|
||||||
wrapper.classList.add("vsc-nosource");
|
wrapper.classList.add("vsc-nosource");
|
||||||
if (tc.settings.startHidden) wrapper.classList.add("vsc-hidden");
|
if (tc.settings.startHidden) wrapper.classList.add("vsc-hidden");
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
:host {
|
:host {
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
top: 0 !important;
|
|
||||||
left: 0 !important;
|
|
||||||
width: 100% !important;
|
|
||||||
height: 100% !important;
|
|
||||||
pointer-events: none !important;
|
pointer-events: none !important;
|
||||||
z-index: 2147483647 !important;
|
z-index: 2147483647 !important;
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
@@ -15,7 +11,6 @@
|
|||||||
base absolute host rule. */
|
base absolute host rule. */
|
||||||
:host(.vsc-fullscreen-popover) {
|
:host(.vsc-fullscreen-popover) {
|
||||||
position: fixed !important;
|
position: fixed !important;
|
||||||
inset: auto !important;
|
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
border: 0 !important;
|
border: 0 !important;
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ const {
|
|||||||
createChromeMock,
|
createChromeMock,
|
||||||
evaluateScript,
|
evaluateScript,
|
||||||
flushAsyncWork,
|
flushAsyncWork,
|
||||||
loadHtmlString
|
loadHtmlString,
|
||||||
|
readWorkspaceFile
|
||||||
} = require("./helpers/extension-test-utils");
|
} = require("./helpers/extension-test-utils");
|
||||||
|
|
||||||
function bootInject(options) {
|
function bootInject(options) {
|
||||||
@@ -280,6 +281,45 @@ describe("inject.js media/controller lifecycle regressions", () => {
|
|||||||
expect(video.vsc.div.style.getPropertyValue("height")).toBe("226px");
|
expect(video.vsc.div.style.getPropertyValue("height")).toBe("226px");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not let shadow host defaults override measured geometry", () => {
|
||||||
|
const shadowCss = readWorkspaceFile("extension/content/shadow.css");
|
||||||
|
const hostRule = shadowCss.match(/:host\s*\{([^}]*)\}/)[1];
|
||||||
|
const fullscreenRule = shadowCss.match(
|
||||||
|
/:host\(\.vsc-fullscreen-popover\)\s*\{([^}]*)\}/
|
||||||
|
)[1];
|
||||||
|
|
||||||
|
expect(hostRule).not.toMatch(/\b(?:top|left|width|height)\s*:/);
|
||||||
|
expect(fullscreenRule).not.toMatch(/\binset\s*:/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("repositions a Shorts controller when playback moves the video on-screen", async () => {
|
||||||
|
vi.useFakeTimers();
|
||||||
|
bootInject({ url: "https://www.youtube.com/shorts/example" });
|
||||||
|
await settleLifecycle();
|
||||||
|
|
||||||
|
const player = document.createElement("div");
|
||||||
|
player.className = "html5-video-player";
|
||||||
|
const video = document.createElement("video");
|
||||||
|
const playerRect = makeRect(40, 64, 351, 624);
|
||||||
|
let videoRect = makeRect(40, -560, 351, 624);
|
||||||
|
|
||||||
|
setRect(player, playerRect);
|
||||||
|
setBoxMetrics(player, playerRect.width, playerRect.height);
|
||||||
|
video.getBoundingClientRect = () => videoRect;
|
||||||
|
video.src = "blob:https://www.youtube.com/shorts";
|
||||||
|
player.appendChild(video);
|
||||||
|
document.body.appendChild(player);
|
||||||
|
|
||||||
|
window.ensureController(video, player);
|
||||||
|
expect(video.vsc.div.style.getPropertyValue("top")).toBe("-624px");
|
||||||
|
|
||||||
|
videoRect = playerRect;
|
||||||
|
video.dispatchEvent(new Event("playing"));
|
||||||
|
await vi.advanceTimersByTimeAsync(0);
|
||||||
|
|
||||||
|
expect(video.vsc.div.style.getPropertyValue("top")).toBe("0px");
|
||||||
|
});
|
||||||
|
|
||||||
it("targets the controller nearest the pointer unless change-all is selected", async () => {
|
it("targets the controller nearest the pointer unless change-all is selected", async () => {
|
||||||
bootInject();
|
bootInject();
|
||||||
await settleLifecycle();
|
await settleLifecycle();
|
||||||
@@ -638,6 +678,25 @@ describe("inject.js media/controller lifecycle regressions", () => {
|
|||||||
controller.controllerHostCleanup();
|
controller.controllerHostCleanup();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps a visible player-local host when Firefox fullscreens the page root", async () => {
|
||||||
|
bootInject();
|
||||||
|
await settleLifecycle();
|
||||||
|
|
||||||
|
const { mount, controller, wrapper } = createControlledVideo();
|
||||||
|
setRect(document.documentElement, makeRect(0, 0, 0, 0));
|
||||||
|
Object.defineProperty(document, "fullscreenElement", {
|
||||||
|
configurable: true,
|
||||||
|
value: document.documentElement
|
||||||
|
});
|
||||||
|
|
||||||
|
window.syncControllerFullscreenMount(controller);
|
||||||
|
|
||||||
|
expect(wrapper.parentElement).toBe(mount);
|
||||||
|
expect(wrapper.classList.contains("vsc-geometry-hidden")).toBe(false);
|
||||||
|
expect(document.documentElement.style.position).toBe("");
|
||||||
|
expect(document.documentElement.style.isolation).toBe("");
|
||||||
|
});
|
||||||
|
|
||||||
it("only promotes the directly-fullscreen video's controller", async () => {
|
it("only promotes the directly-fullscreen video's controller", async () => {
|
||||||
bootInject();
|
bootInject();
|
||||||
await settleLifecycle();
|
await settleLifecycle();
|
||||||
|
|||||||
Reference in new issue
Block a user