Skip to content

Commit e7b45be

Browse files
authored
refactor: simplify fullscreen toggle button, fix minimize not working reliably on some browsers
fix #901" " * fix: simplify fullscreen JavaScript toggle-button * fix: make Godot full-screen button transparent instead of turning off visibility
1 parent 791b1dd commit e7b45be

File tree

7 files changed

+108
-281
lines changed

7 files changed

+108
-281
lines changed

autoload/Globals.gd

-39
This file was deleted.

html_export/static/bootstrap.d.ts

+1-10
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,8 @@ interface GDQuestLib {
33
displayFailureNotice: (err: Error | string) => void;
44
log: Log;
55
makeLogger: (title: string) => Console;
6-
fullScreen: {
7-
isIt: {
8-
checkFullScreenElement: () => boolean;
9-
checkCSSMediaQuery: () => boolean;
10-
checkWindowMargins: () => boolean;
11-
};
12-
toggle: () => void;
13-
};
146
events: {
157
onError: Signal;
16-
onFullScreen: Signal;
178
onGodotLoaded: Signal;
189
onResize: Signal;
1910
};
@@ -83,7 +74,7 @@ declare const GODOT_CONFIG: {
8374
};
8475

8576
declare const Engine: {
86-
new (config: typeof GODOT_CONFIG): GodotEngineInstance;
77+
new(config: typeof GODOT_CONFIG): GodotEngineInstance;
8778
isWebGLAvailable: () => boolean;
8879
};
8980

html_export/static/bootstrap.js

+67-184
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ window.GDQUEST = ((/** @type {GDQuestLib} */ GDQUEST) => {
1010
document.getElementById("canvas-frame")
1111
);
1212

13-
const noOp = () => {};
13+
const noOp = () => { };
1414

1515
const throttle = (callback, limit = 50) => {
1616
let waiting = false;
@@ -26,14 +26,14 @@ window.GDQUEST = ((/** @type {GDQuestLib} */ GDQUEST) => {
2626

2727
const aspectRatio =
2828
(maxW = 0, maxH = 0) =>
29-
(currentWidth = window.innerWidth, currentHeight = window.innerHeight) => {
30-
const ratioW = currentWidth / maxW;
31-
const ratioH = currentHeight / maxH;
32-
const ratio = Math.min(ratioW, ratioH);
33-
const width = maxW * ratio;
34-
const height = maxH * ratio;
35-
return { width, height, ratio };
36-
};
29+
(currentWidth = window.innerWidth, currentHeight = window.innerHeight) => {
30+
const ratioW = currentWidth / maxW;
31+
const ratioH = currentHeight / maxH;
32+
const ratio = Math.min(ratioW, ratioH);
33+
const width = maxW * ratio;
34+
const height = maxH * ratio;
35+
return { width, height, ratio };
36+
};
3737

3838
/**
3939
* Returns a proxied console that can be turned off and on by appending
@@ -124,7 +124,6 @@ window.GDQUEST = ((/** @type {GDQuestLib} */ GDQUEST) => {
124124
GDQUEST.events = {
125125
onError: makeSignal(),
126126
onGodotLoaded: makeSignal(),
127-
onFullScreen: makeSignal(),
128127
onResize: makeSignal(),
129128
};
130129

@@ -356,45 +355,45 @@ window.GDQUEST = ((/** @type {GDQuestLib} */ GDQUEST) => {
356355

357356
const makeLogFunction =
358357
(level = LEVELS.INFO) =>
359-
/** @type {LogFunction} */
360-
(anything, msg = "") => {
361-
if (typeof anything === "string" || typeof anything === "number") {
362-
msg = String(anything);
363-
anything = null;
364-
}
365-
366-
const time = Date.now();
367-
/** @type {LogLine} */
368-
const log_line = { time, level, msg, ...(anything || {}) };
369-
log_lines.push(log_line);
370-
localStorage.setItem(KEY, JSON.stringify(log_lines));
371-
372-
if (level < 30) {
373-
if (anything) {
374-
debug.log(msg, anything);
375-
} else {
376-
debug.log(msg);
377-
}
378-
} else if (level < 40) {
379-
if (anything) {
380-
debug.info(msg, anything);
381-
} else {
382-
debug.info(msg);
383-
}
384-
} else if (level < 50) {
385-
if (anything) {
386-
debug.warn(msg, anything);
387-
} else {
388-
debug.warn(msg);
358+
/** @type {LogFunction} */
359+
(anything, msg = "") => {
360+
if (typeof anything === "string" || typeof anything === "number") {
361+
msg = String(anything);
362+
anything = null;
389363
}
390-
} else {
391-
if (anything) {
392-
debug.error(msg, anything);
364+
365+
const time = Date.now();
366+
/** @type {LogLine} */
367+
const log_line = { time, level, msg, ...(anything || {}) };
368+
log_lines.push(log_line);
369+
localStorage.setItem(KEY, JSON.stringify(log_lines));
370+
371+
if (level < 30) {
372+
if (anything) {
373+
debug.log(msg, anything);
374+
} else {
375+
debug.log(msg);
376+
}
377+
} else if (level < 40) {
378+
if (anything) {
379+
debug.info(msg, anything);
380+
} else {
381+
debug.info(msg);
382+
}
383+
} else if (level < 50) {
384+
if (anything) {
385+
debug.warn(msg, anything);
386+
} else {
387+
debug.warn(msg);
388+
}
393389
} else {
394-
debug.error(msg);
390+
if (anything) {
391+
debug.error(msg, anything);
392+
} else {
393+
debug.error(msg);
394+
}
395395
}
396-
}
397-
};
396+
};
398397

399398
/** @type { Log['display'] } */
400399
const display = () => console.table(get());
@@ -466,163 +465,47 @@ window.GDQUEST = ((/** @type {GDQuestLib} */ GDQUEST) => {
466465
}
467466

468467
fullscreen: {
469-
const debug = makeLogger("fullscreen");
470-
/**
471-
* Browsers make it exceedingly hard to get that information reliably, so
472-
* we have to rely on a bunch of different strategies
468+
/*
469+
* Create a button with a label.
473470
*/
474-
const isIt = (() => {
475-
/**
476-
* This is an invisible element which changes position when the browser
477-
* is full screen. We do this through the media query:
478-
* ```css
479-
* @media all and (display-mode: fullscreen) {
480-
* #fullscreen-detector {
481-
* top: 1px;
482-
* }
483-
* }
484-
* ```
485-
*/
486-
const fullScreenPoller = (() => {
487-
const el = document.createElement("div");
488-
el.id = "fullscreen-detector";
489-
document.body.appendChild(el);
490-
return el;
491-
})();
492-
493-
/** check is the element has moved */
494-
const checkCSSMediaQuery = () => {
495-
const top = fullScreenPoller.getBoundingClientRect().top > 0;
496-
return top;
497-
};
498-
499-
/** check if browser has borders. Take zoom into account */
500-
const checkWindowMargins = () => {
501-
const zoom = window.outerWidth / window.innerWidth;
502-
const hasMargin =
503-
Math.abs(window.innerWidth * zoom - screen.width) < 10;
504-
return hasMargin;
505-
};
506-
507-
/** check if some element has been set fullscreen through the JS API */
508-
const checkFullScreenElement = () => {
509-
const hasSomeFullScreenElement = document.fullscreenElement !== null;
510-
return hasSomeFullScreenElement;
511-
};
512-
513-
return {
514-
checkFullScreenElement,
515-
checkCSSMediaQuery,
516-
checkWindowMargins,
517-
};
518-
})();
519-
520-
let isFullScreen = false;
521-
let wasFullScreen = false;
522-
523-
/** use the JS API to call fullscreen */
524-
const toggle = () => {
525-
//debug.info(`will`, isFullScreen ? "exit" : "enter", "fullscreen mode");
526-
const isItActuallyFullScreen = isIt.checkCSSMediaQuery();
527-
if (isItActuallyFullScreen !== isFullScreen) {
528-
debug.error(
529-
`Mismatch! Expected fullscreen to be ${isFullScreen}, but it is ${isItActuallyFullScreen}.`
530-
);
531-
if (isItActuallyFullScreen) {
532-
debug.error(
533-
`Cannot exit a fullscreen mode set natively. Bailing out!`
534-
);
535-
return;
536-
} else {
537-
debug.warn(`Will set our fullscreen now`);
538-
isFullScreen = false;
539-
}
540-
}
541-
isFullScreen
542-
? document.exitFullscreen()
543-
: document.documentElement.requestFullscreen();
544-
isFullScreen = !isFullScreen;
545-
};
546-
547-
/**
548-
* Create a button with the proper classes; change class when
549-
* fullscreen event happens
550-
*/
551-
const button = (() => {
552-
const normalClassName = "button-fullscreen";
553-
471+
const makeFullscreenButton = (className, onClick = () => { }) => {
554472
const button = document.createElement("button");
555-
button.classList.add(normalClassName);
556-
button.addEventListener("click", toggle);
473+
button.classList.add(className);
474+
button.addEventListener("click", onClick);
557475

558476
const label = document.createElement("span");
559477
label.textContent = "toggle Fullscreen";
560478
button.appendChild(label);
561479
return button;
562-
})();
480+
}
563481

564482
/**
565-
* Only add the button if Godot has loaded
483+
* Create a button with the proper classes; change class when
484+
* fullscreen event happens
566485
*/
567-
GDQUEST.events.onGodotLoaded.once(() => {
568-
canvasContainer.appendChild(button);
486+
const fullscreenOnButton = makeFullscreenButton("button-fullscreen-on", () => document.documentElement.requestFullscreen());
487+
const fullscreenOffButton = makeFullscreenButton("button-fullscreen-off", () => {
488+
document.exitFullscreen().catch((err) => err.name !== "TypeError" && console.error(err));
569489
});
570490

571491
/**
572-
* Checks if the actual fullscreen state was set through an API
573-
* If we're _exiting_ fullscreen, then we can't check, but we
574-
* set `isFullScreen` to `false`.
575-
* @param {boolean} isItActuallyFullScreen
576-
*/
577-
const wasItOurFullScreen = (isItActuallyFullScreen) => {
578-
if (isItActuallyFullScreen) {
579-
if (isIt.checkFullScreenElement()) {
580-
debug.log("full screen changed through our button");
581-
} else {
582-
// that means fullscreen was set _not_ through our button
583-
debug.warn("full screen changed through shortcut, hiding the button");
584-
document.body.classList.add("native-fullscreen");
585-
}
586-
} else {
587-
debug.log("exiting fullscreen");
588-
isFullScreen = false;
589-
document.body.classList.remove("native-fullscreen");
590-
}
591-
};
592-
593-
/**
594-
* @param {Event} evt
492+
* Only add the button if Godot has loaded
595493
*/
596-
const onFullScreenChange = (evt) => {
597-
const isItActuallyFullScreen = isIt.checkFullScreenElement();
598-
if (isItActuallyFullScreen != wasFullScreen) {
599-
wasFullScreen = isItActuallyFullScreen;
600-
debug.info(`[ ${evt.type} ]`, `full screen state changed`);
601-
const wasIt = wasItOurFullScreen(isItActuallyFullScreen);
602-
GDQUEST.events.onFullScreen.emit(isItActuallyFullScreen, wasIt);
603-
}
604-
};
494+
GDQUEST.events.onGodotLoaded.once(() => {
495+
canvasContainer.appendChild(fullscreenOnButton);
496+
canvasContainer.appendChild(fullscreenOffButton);
497+
});
605498

606499
document.addEventListener("keydown", (event) => {
607-
if (event.code == `F11`) {
500+
if (event.code === "F11") {
608501
event.preventDefault();
609-
button.focus();
610-
debug.log("Stopped F11");
502+
if (getComputedStyle(fullscreenOnButton).display !== "none") {
503+
fullscreenOnButton.click();
504+
} else if (getComputedStyle(fullscreenOffButton).display !== "none") {
505+
fullscreenOffButton.click();
506+
}
611507
}
612508
});
613-
614-
/**
615-
* This is for when using the JS API
616-
*/
617-
document.addEventListener("fullscreenchange", onFullScreenChange);
618-
/**
619-
* This is for buttons, shortcuts, and other methods for setting fullscreen.
620-
* We could also potentially poll for size after keypresses, but this seems
621-
* to work well enough
622-
*/
623-
GDQUEST.events.onResize.connect(onFullScreenChange);
624-
625-
GDQUEST.fullScreen = { isIt, toggle };
626509
}
627510

628511
return GDQUEST;

0 commit comments

Comments
 (0)