diff --git a/platform/chromium/vapi-background.js b/platform/chromium/vapi-background.js index 517b0854f..42dc2e27d 100644 --- a/platform/chromium/vapi-background.js +++ b/platform/chromium/vapi-background.js @@ -701,7 +701,7 @@ vAPI.setIcon = (function() { chrome.browserAction.onClicked.addListener(function(tab) { vAPI.tabs.open({ select: true, - url: 'popup.html?tabId=' + tab.id + '&mobile=1' + url: 'popup.html?tabId=' + tab.id + '&responsive=1' }); }); diff --git a/src/css/popup.css b/src/css/popup.css index 12b0b8e1d..922b249c8 100644 --- a/src/css/popup.css +++ b/src/css/popup.css @@ -1,25 +1,15 @@ body { background-color: white; border: 0; - float: left; + display: flex; + flex-direction: column; margin: 0; opacity: 1; overflow: hidden; padding: 0; white-space: nowrap; - } -body.fullsize { - overflow: auto; - } -body.mobile { - overflow-y: auto; - } -/** - https://github.com/gorhill/uBlock/issues/83 - .portrait = portrait mode = width is constrained = optimize layout accordingly. - */ -body.portrait { - width: 100%; + width: fit-content; + width: -moz-fit-content; } h2 { @@ -50,30 +40,22 @@ a { padding: calc(0.1em + 1px) 0; position: relative; text-align: center; + width: 100%; } #version { font-size: 90%; font-weight: normal; } -body[dir="ltr"] #panes { - direction: rtl; - } -body[dir="rtl"] #panes { - direction: ltr; - } -body, #panes { - text-align: right; /* this helps the popup render better at "intermediate" widths */ - } +#panes { + display: flex; + flex-direction: row-reverse; + } #panes > div { display: inline-block; position: relative; vertical-align: top; } -body.portrait #panes > div { - display: block; - width: 100%; - } body[dir="ltr"] #panes > div { direction: ltr; } @@ -81,6 +63,7 @@ body[dir="rtl"] #panes > div { direction: rtl; } #panes > div:nth-of-type(2) { + flex-shrink: 0; font-family: "Noto Sans", sans-serif; overflow-y: auto; overflow-x: hidden; @@ -93,14 +76,7 @@ body[dir="ltr"] #panes > div:nth-of-type(2) { direction: rtl; margin-right: 1px; } -/** - Scroll bar to the right. - Firefox bug: when popup is rendered inside hamburger menu panel, Firefox is - unable to render the scroll bar to the left. - Maybe ? - */ -body[dir="rtl"] #panes > div:nth-of-type(2), -body.portrait[dir="ltr"] #panes > div:nth-of-type(2) { +body[dir="rtl"] #panes > div:nth-of-type(2) { direction: ltr; margin-left: 1px; } @@ -543,3 +519,21 @@ body.advancedUser #firewallContainer > div > span.noopRule.ownRule { #firewallContainer.dirty ~ #rulesetTools > span:hover { color: black; } + + +body.responsive { + overflow-y: auto; + width: auto; + } +body.responsive #panes { + flex-wrap: wrap; + } +body.responsive #panes > div:nth-of-type(1) { + flex-shrink: 0; + flex-grow: 1; + } +body.responsive #panes > div:nth-of-type(2) { + flex-grow: 8; + flex-shrink: 1; + width: auto; + } diff --git a/src/js/popup.js b/src/js/popup.js index 01d17ef20..61539881d 100644 --- a/src/js/popup.js +++ b/src/js/popup.js @@ -40,9 +40,13 @@ if ( typeof popupFontSize === 'string' && popupFontSize !== 'unset' ) { var dfPaneVisibleStored = vAPI.localStorage.getItem('popupFirewallPane') === 'true'; -// No restriction on vertical size? -if ( /[\?&]fullsize=1/.test(window.location.search) ) { - document.body.classList.add('fullsize'); +// Popup panel can be in one of two modes: +// - not responsive: viewport is expected to adjust to popup panel size +// - responsive: popup panel must adjust to viewport size -- this happens when +// the viewport is not resized by the browser to perfectly fits uBO's popup +// panel. +if ( /[\?&]responsive=1/.test(window.location.search) ) { + document.body.classList.add('responsive'); } // Mobile device? @@ -50,29 +54,10 @@ if ( /[\?&]fullsize=1/.test(window.location.search) ) { // - If at least one of the window's viewport dimension is larger than the // corresponding device's screen dimension, assume uBO's popup panel sits in // its own tab. -if ( - /[\?&]mobile=1/.test(window.location.search) || - window.innerWidth >= window.screen.availWidth || - window.innerHeight >= window.screen.availHeight -) { - document.body.classList.add('mobile'); +if ( vAPI.webextFlavor.soup.has('mobile') ) { + document.body.classList.add('responsive'); } -// The padlock/eraser must be manually positioned: -// - Its vertical position depends on the height of the popup title bar -// - Its horizontal position depends on whether there is a vertical scrollbar. -var positionRulesetTools = function() { - var vpos = document.getElementById('appinfo') - .getBoundingClientRect() - .bottom + window.scrollY + 3; - var hpos = document.getElementById('firewallContainer') - .getBoundingClientRect() - .left + window.scrollX + 3; - var style = document.getElementById('rulesetTools').style; - style.setProperty('top', (vpos >>> 0) + 'px'); - style.setProperty('left', (hpos >>> 0) + 'px'); -}; - // https://github.com/chrisaljoudi/uBlock/issues/996 // Experimental: mitigate glitchy popup UI: immediately set the firewall pane // visibility to its last known state. By default the pane is hidden. @@ -115,6 +100,24 @@ var reCyrillicAmbiguous = /[\u042c\u0430\u0433\u0435\u043e\u043f\u0440\u0441\u04 /******************************************************************************/ +// The padlock/eraser must be manually positioned: +// - Its vertical position depends on the height of the popup title bar +// - Its horizontal position depends on whether there is a vertical scrollbar. + +var positionRulesetTools = function() { + var vpos = document.getElementById('appinfo') + .getBoundingClientRect() + .bottom + window.scrollY + 3; + var hpos = document.getElementById('firewallContainer') + .getBoundingClientRect() + .left + window.scrollX + 3; + var style = document.getElementById('rulesetTools').style; + style.setProperty('top', (vpos >>> 0) + 'px'); + style.setProperty('left', (hpos >>> 0) + 'px'); +}; + +/******************************************************************************/ + var cachePopupData = function(data) { popupData = {}; scopeToSrcHostnameMap['.'] = ''; @@ -584,43 +587,47 @@ var renderOnce = function() { uDom('#firewallContainer [data-i18n-tip][data-src]').removeAttr('data-tip'); } + // https://github.com/gorhill/uBlock/issues/2274 + // Make use of the whole viewport when in responsive mode. + if ( document.body.classList.contains('responsive') ) { return; } + // For large displays: we do not want the left pane -- optional and // hidden by defaut -- to dictate the height of the popup. The right pane // dictates the height of the popup, and the left pane will have a // scrollbar if ever its height is more than what is available. // For small displays: we use the whole viewport. - var panes = uDom.nodeFromId('panes'), - rpane = uDom.nodeFromSelector('#panes > div:first-of-type'), + let rpane = uDom.nodeFromSelector('#panes > div:first-of-type'), lpane = uDom.nodeFromSelector('#panes > div:last-of-type'); - var fillViewport = function() { - var newHeight = Math.max( - window.innerHeight - uDom.nodeFromSelector('#appinfo').offsetHeight, - rpane.offsetHeight - ); - if ( newHeight !== lpane.offsetHeight ) { - lpane.style.setProperty('height', newHeight + 'px'); - } - // https://github.com/gorhill/uBlock/issues/3038 - // - Resize the firewall pane while minding the space between the panes. - var newWidth = window.innerWidth - panes.offsetWidth + lpane.offsetWidth; - if ( newWidth !== lpane.offsetWidth ) { - lpane.style.setProperty('width', newWidth + 'px'); + lpane.style.setProperty('height', rpane.offsetHeight + 'px'); + + // Be prepared to fall into responsive mode if ever it is found the + // viewport is not a perfect match for the popup panel. + + let resizeTimer; + let resize = function() { + resizeTimer = undefined; + // Do not use equality, fractional pixel dimension occurs and must + // be ignored. + if ( + Math.abs(document.body.offsetWidth - window.innerWidth) < 2 && + Math.abs(document.body.offsetHeight - window.innerHeight) < 2 + ) { + return; } + document.body.classList.add('responsive'); + lpane.style.removeProperty('height'); + window.removeEventListener('resize', resizeAsync); }; - - // https://github.com/gorhill/uBlock/issues/2274 - // Make use of the whole viewport on mobile devices. - if ( document.body.classList.contains('mobile') ) { - fillViewport(); - window.addEventListener('resize', fillViewport); - return; - } - - if ( document.body.classList.contains('fullsize') === false ) { - lpane.style.setProperty('height', rpane.offsetHeight + 'px'); - } + let resizeAsync = function() { + if ( resizeTimer !== undefined ) { + clearTimeout(resizeTimer); + } + resizeTimer = vAPI.setTimeout(resize, 67); + }; + window.addEventListener('resize', resizeAsync); + resizeAsync(); }; /******************************************************************************/ @@ -864,7 +871,7 @@ var toggleMinimize = function(ev) { { what: 'gotoURL', details: { - url: 'popup.html?tabId=' + popupData.tabId + '&fullsize=1', + url: 'popup.html?tabId=' + popupData.tabId + '&responsive=1', select: true, index: -1 } @@ -1066,31 +1073,31 @@ var onHideTooltip = function() { (function() { // If there's no tab id specified in the query string, // it will default to current tab. - var tabId = null; + let tabId = null; // Extract the tab id of the page this popup is for - var matches = window.location.search.match(/[\?&]tabId=([^&]+)/); + let matches = window.location.search.match(/[\?&]tabId=([^&]+)/); if ( matches && matches.length === 2 ) { tabId = parseInt(matches[1], 10) || 0; } getPopupData(tabId); - - uDom('#switch').on('click', toggleNetFilteringSwitch); - uDom('#gotoZap').on('click', gotoZap); - uDom('#gotoPick').on('click', gotoPick); - uDom('h2').on('click', toggleFirewallPane); - uDom('#refresh').on('click', reloadTab); - uDom('.hnSwitch').on('click', toggleHostnameSwitch); - uDom('#saveRules').on('click', saveFirewallRules); - uDom('#revertRules').on('click', revertFirewallRules); - uDom('[data-i18n="popupAnyRulePrompt"]').on('click', toggleMinimize); - - uDom('body').on('mouseenter', '[data-tip]', onShowTooltip) - .on('mouseleave', '[data-tip]', onHideTooltip); - - uDom('a[href]').on('click', gotoURL); })(); +uDom('#switch').on('click', toggleNetFilteringSwitch); +uDom('#gotoZap').on('click', gotoZap); +uDom('#gotoPick').on('click', gotoPick); +uDom('h2').on('click', toggleFirewallPane); +uDom('#refresh').on('click', reloadTab); +uDom('.hnSwitch').on('click', toggleHostnameSwitch); +uDom('#saveRules').on('click', saveFirewallRules); +uDom('#revertRules').on('click', revertFirewallRules); +uDom('[data-i18n="popupAnyRulePrompt"]').on('click', toggleMinimize); + +uDom('body').on('mouseenter', '[data-tip]', onShowTooltip) + .on('mouseleave', '[data-tip]', onHideTooltip); + +uDom('a[href]').on('click', gotoURL); + /******************************************************************************/ })(); diff --git a/src/popup.html b/src/popup.html index b85e1e49d..dfb8089b2 100644 --- a/src/popup.html +++ b/src/popup.html @@ -2,8 +2,8 @@ - +