diff --git a/web/plugin.head.html b/web/plugin.head.html index f8a5c06..958313d 100644 --- a/web/plugin.head.html +++ b/web/plugin.head.html @@ -48,11 +48,13 @@ box-sizing: border-box !important; height: calc(100% - var(--politictalk-stage-top-inset, 96px) - var(--politictalk-stage-bottom-inset, 128px)) !important; left: var(--politictalk-stage-side-inset, 8px) !important; + overflow: hidden !important; right: var(--politictalk-stage-side-inset, 8px) !important; top: var(--politictalk-stage-top-inset, 96px) !important; width: auto !important; } + html.politictalk-stage-brand-inset:not(.politictalk-direct-access-blocked) #videospace > span, html.politictalk-stage-brand-inset:not(.politictalk-direct-access-blocked) #videospace .filmstrip, html.politictalk-stage-brand-inset:not(.politictalk-direct-access-blocked) #videospace #remoteVideos, html.politictalk-stage-brand-inset:not(.politictalk-direct-access-blocked) #videospace .filmstrip__videos, @@ -1274,6 +1276,30 @@ return Math.max(0, rect.width) * Math.max(0, rect.height); } + function setPoliticTalkImportantStyle(element, property, value) { + if (!element || !element.style) { + return; + } + + element.style.setProperty(property, value, 'important'); + } + + function getPoliticTalkNumericStyle(element, property, fallback) { + if (!element) { + return fallback; + } + + var inlineValue = Number.parseFloat(element.style && element.style.getPropertyValue(property)); + + if (Number.isFinite(inlineValue)) { + return inlineValue; + } + + var computedValue = Number.parseFloat(window.getComputedStyle(element).getPropertyValue(property)); + + return Number.isFinite(computedValue) ? computedValue : fallback; + } + function isPoliticTalkTileCandidate(element, stageRect) { if (!element || element === document.body || element.id === 'videospace') { return false; @@ -1429,6 +1455,86 @@ && backgroundColor !== 'transparent'; } + function getPoliticTalkAvailableTileHeight(videospace) { + var videospaceRect = videospace.getBoundingClientRect(); + var toolbar = getVisiblePoliticTalkToolbar(); + var viewportBottom = window.visualViewport + ? Math.min(window.innerHeight, window.visualViewport.offsetTop + window.visualViewport.height) + : window.innerHeight; + var toolbarTop = toolbar ? toolbar.getBoundingClientRect().top : viewportBottom; + var bottomLimit = Math.min(videospaceRect.bottom, toolbarTop - 18, viewportBottom - 18); + var availableHeight = Math.floor(bottomLimit - videospaceRect.top); + + return Math.max(180, availableHeight); + } + + function applyPoliticTalkTileLayout(videospace, tiles) { + if (!videospace || !tiles.length) { + return; + } + + var remoteVideos = videospace.querySelector('.remote-videos'); + var remoteVideosInner = remoteVideos && remoteVideos.firstElementChild; + var availableHeight = getPoliticTalkAvailableTileHeight(videospace); + var tileMetrics = tiles.map(function(tile) { + var rect = tile.getBoundingClientRect(); + var top = getPoliticTalkNumericStyle(tile, 'top', 0); + var height = getPoliticTalkNumericStyle(tile, 'height', rect.height); + + return { + height: Math.max(1, height), + tile: tile, + top: Number.isFinite(top) ? top : 0 + }; + }); + var minTop = Math.min.apply(null, tileMetrics.map(function(metric) { + return metric.top; + })); + var maxBottom = Math.max.apply(null, tileMetrics.map(function(metric) { + return metric.top + metric.height; + })); + var contentHeight = Math.max(1, maxBottom - minTop); + var scale = Math.min(1, availableHeight / contentHeight); + var nextContentHeight = Math.max(1, Math.floor(contentHeight * scale)); + + [ + videospace.querySelector('.filmstrip'), + videospace.querySelector('#remoteVideos'), + remoteVideos, + remoteVideosInner + ].forEach(function(container) { + if (!container) { + return; + } + + setPoliticTalkImportantStyle(container, 'height', availableHeight + 'px'); + setPoliticTalkImportantStyle(container, 'max-height', availableHeight + 'px'); + setPoliticTalkImportantStyle(container, 'min-height', '0px'); + setPoliticTalkImportantStyle(container, 'overflow', 'hidden'); + }); + + if (remoteVideosInner) { + setPoliticTalkImportantStyle(remoteVideosInner, 'height', nextContentHeight + 'px'); + setPoliticTalkImportantStyle(remoteVideosInner, 'max-height', nextContentHeight + 'px'); + } + + tileMetrics.forEach(function(metric) { + var nextTop = Math.max(0, Math.round((metric.top - minTop) * scale)); + var nextHeight = Math.max(120, Math.floor(metric.height * scale)); + + if (nextTop + nextHeight > availableHeight) { + nextHeight = Math.max(120, availableHeight - nextTop); + } + + setPoliticTalkImportantStyle(metric.tile, 'top', nextTop + 'px'); + setPoliticTalkImportantStyle(metric.tile, 'height', nextHeight + 'px'); + setPoliticTalkImportantStyle(metric.tile, 'min-height', nextHeight + 'px'); + setPoliticTalkImportantStyle(metric.tile, 'max-height', nextHeight + 'px'); + setPoliticTalkImportantStyle(metric.tile, 'box-sizing', 'border-box'); + setPoliticTalkImportantStyle(metric.tile, 'overflow', 'hidden'); + }); + } + function applyPoliticTalkTileTheme() { if (directAccessBlocked || !document.body) { return; @@ -1451,7 +1557,11 @@ ); }); - getPoliticTalkTileCandidates(videospace).forEach(function(tile) { + var tiles = getPoliticTalkTileCandidates(videospace); + + applyPoliticTalkTileLayout(videospace, tiles); + + tiles.forEach(function(tile) { tile.classList.add('politictalk-themed-tile'); tile.querySelectorAll('div, span').forEach(function(candidate) { @@ -1481,6 +1591,14 @@ return; } + window.addEventListener('resize', applyPoliticTalkTileTheme, { passive: true }); + window.addEventListener('orientationchange', applyPoliticTalkTileTheme, { passive: true }); + + if (window.visualViewport) { + window.visualViewport.addEventListener('resize', applyPoliticTalkTileTheme, { passive: true }); + window.visualViewport.addEventListener('scroll', applyPoliticTalkTileTheme, { passive: true }); + } + window.politicTalkTileThemeObserver = new MutationObserver(function() { window.cancelAnimationFrame(window.politicTalkTileThemeFrame); window.politicTalkTileThemeFrame = window.requestAnimationFrame(applyPoliticTalkTileTheme);