Skip to content

Instantly share code, notes, and snippets.

@gartnera
Created March 13, 2025 17:56
Show Gist options
  • Save gartnera/80112cb67ddfbcc9d9122edfe53704bd to your computer and use it in GitHub Desktop.
Save gartnera/80112cb67ddfbcc9d9122edfe53704bd to your computer and use it in GitHub Desktop.
Virtualize the Fullscreen API to expand elements without using native fullscreen. This is useful when using a window manager that doesn't like it when windows try to go fullscreen.
// ==UserScript==
// @name Fullscreen API Virtualizer
// @namespace https://agartner.com
// @version 1.0
// @description Virtualize the Fullscreen API to expand elements without using native fullscreen
// @author You
// @match *://*/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
// Add CSS for virtualized fullscreen
document.head.appendChild(Object.assign(document.createElement('style'), {
textContent: `
.virtualized-fullscreen {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100vw !important;
height: 100vh !important;
z-index: 2147483647 !important;
background-color: black !important;
margin: 0 !important;
padding: 0 !important;
border: none !important;
box-sizing: border-box !important;
}
`
}));
// Track fullscreen state
const fullscreenState = {
active: false,
element: null,
originalStyles: null
};
// Style management functions
function saveOriginalStyles(element) {
const stylesToSave = ['position', 'top', 'left', 'width', 'height', 'zIndex',
'backgroundColor', 'margin', 'padding', 'border', 'boxSizing'];
const originalStyles = {};
stylesToSave.forEach(prop => {
originalStyles[prop] = element.style[prop];
});
return originalStyles;
}
function restoreOriginalStyles(element, styles) {
Object.keys(styles).forEach(prop => {
element.style[prop] = styles[prop];
});
}
// Virtual fullscreen implementation
function virtualRequestFullscreen() {
if (fullscreenState.active) return Promise.resolve();
const element = this;
fullscreenState.element = element;
fullscreenState.originalStyles = saveOriginalStyles(element);
fullscreenState.active = true;
element.classList.add('virtualized-fullscreen');
document.dispatchEvent(new Event('fullscreenchange'));
return Promise.resolve();
}
function virtualExitFullscreen() {
if (!fullscreenState.active) return Promise.resolve();
const element = fullscreenState.element;
element.classList.remove('virtualized-fullscreen');
restoreOriginalStyles(element, fullscreenState.originalStyles);
fullscreenState.active = false;
fullscreenState.element = null;
fullscreenState.originalStyles = null;
document.dispatchEvent(new Event('fullscreenchange'));
return Promise.resolve();
}
// Helper function to override methods safely
function overrideMethod(object, methodName, newImplementation) {
if (typeof object[methodName] === 'function') {
object[methodName] = newImplementation;
}
}
// Helper function to override getters safely
function overrideGetter(object, propertyName, getter) {
if (Object.getOwnPropertyDescriptor(object, propertyName)) {
Object.defineProperty(object, propertyName, { get: getter });
}
}
// Override request methods
const requestMethods = ['requestFullscreen', 'mozRequestFullScreen',
'webkitRequestFullscreen', 'msRequestFullscreen'];
requestMethods.forEach(method => {
overrideMethod(Element.prototype, method, virtualRequestFullscreen);
});
// Override exit methods
const exitMethods = ['exitFullscreen', 'mozCancelFullScreen',
'webkitExitFullscreen', 'msExitFullscreen'];
exitMethods.forEach(method => {
overrideMethod(Document.prototype, method, virtualExitFullscreen);
});
// Override element getters
const elementGetters = ['fullscreenElement', 'webkitFullscreenElement',
'mozFullScreenElement', 'msFullscreenElement'];
elementGetters.forEach(getter => {
overrideGetter(Document.prototype, getter, function() {
return fullscreenState.active ? fullscreenState.element : null;
});
});
// Override enabled getters
const enabledGetters = ['fullscreenEnabled', 'webkitFullscreenEnabled',
'mozFullScreenEnabled', 'msFullscreenEnabled'];
enabledGetters.forEach(getter => {
overrideGetter(Document.prototype, getter, function() {
return true;
});
});
// Add Escape key handler
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape' && fullscreenState.active) {
virtualExitFullscreen();
}
});
console.log('Fullscreen API Virtualizer loaded successfully!');
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment