|
2918 | 2918 | /** @type {boolean} */ |
2919 | 2919 | #isDebugFlagSet = false |
2920 | 2920 |
|
2921 | | - /** @type {{ debug?: boolean, featureSettings?: Record<string, unknown>, assets?: AssetConfig | undefined, site: Site, messagingConfig?: import('@duckduckgo/messaging').MessagingConfig } | null} */ |
| 2921 | + /** @type {{ debug?: boolean, desktopModeEnabled?: boolean, featureSettings?: Record<string, unknown>, assets?: AssetConfig | undefined, site: Site, messagingConfig?: import('@duckduckgo/messaging').MessagingConfig } | null} */ |
2922 | 2922 | #args |
2923 | 2923 |
|
2924 | 2924 | constructor (featureName) { |
|
2931 | 2931 | return this.#args?.debug || false |
2932 | 2932 | } |
2933 | 2933 |
|
| 2934 | + get desktopModeEnabled () { |
| 2935 | + return this.#args?.desktopModeEnabled || false |
| 2936 | + } |
| 2937 | + |
2934 | 2938 | /** |
2935 | 2939 | * @param {import('./utils').Platform} platform |
2936 | 2940 | */ |
@@ -14068,15 +14072,48 @@ |
14068 | 14072 | } |
14069 | 14073 |
|
14070 | 14074 | viewportWidthFix () { |
14071 | | - const viewportTag = document.querySelector('meta[name=viewport]'); |
14072 | | - if (!viewportTag) return |
14073 | | - const viewportContent = viewportTag.getAttribute('content'); |
14074 | | - if (!viewportContent) return |
14075 | | - const viewportContentParts = viewportContent.split(','); |
14076 | | - const widthPart = viewportContentParts.find((part) => part.includes('width')); |
14077 | | - // If we already have a width, don't add one |
14078 | | - if (widthPart) return |
14079 | | - viewportTag.setAttribute('content', `${viewportContent},width=device-width`); |
| 14075 | + const viewportTags = document.querySelectorAll('meta[name=viewport]'); |
| 14076 | + // Chrome respects only the last viewport tag |
| 14077 | + let viewportTag = viewportTags.length === 0 ? null : viewportTags[viewportTags.length - 1]; |
| 14078 | + const viewportContent = viewportTag?.getAttribute('content') || ''; |
| 14079 | + const viewportContentParts = viewportContent ? viewportContent.split(/,|;/) : []; |
| 14080 | + const parsedViewportContent = viewportContentParts.map((part) => { |
| 14081 | + const [key, value] = part.split('=').map(p => p.trim().toLowerCase()); |
| 14082 | + return [key, value] |
| 14083 | + }); |
| 14084 | + if (!viewportTag || this.desktopModeEnabled) { |
| 14085 | + // force wide viewport width |
| 14086 | + const viewportTagExists = Boolean(viewportTag); |
| 14087 | + if (!viewportTag) { |
| 14088 | + viewportTag = document.createElement('meta'); |
| 14089 | + viewportTag.setAttribute('name', 'viewport'); |
| 14090 | + } |
| 14091 | + const forcedWidth = screen.width >= 1280 ? 1280 : 980; |
| 14092 | + // Race condition: depending on the loading state of the page, initial scale may or may not be respected, so the page may look zoomed-in after applying this hack. |
| 14093 | + // Usually this is just an annoyance, but it may be a bigger issue if user-scalable=no is set, so we remove it too. |
| 14094 | + const forcedInitialScale = (screen.width / forcedWidth).toFixed(3); |
| 14095 | + let newContent = `width=${forcedWidth}, initial-scale=${forcedInitialScale}`; |
| 14096 | + parsedViewportContent.forEach(([key], idx) => { |
| 14097 | + if (!['width', 'initial-scale', 'user-scalable'].includes(key)) { |
| 14098 | + newContent = newContent.concat(`,${viewportContentParts[idx]}`); // reuse the original values, not the parsed ones |
| 14099 | + } |
| 14100 | + }); |
| 14101 | + viewportTag.setAttribute('content', newContent); |
| 14102 | + if (!viewportTagExists) { |
| 14103 | + document.head.appendChild(viewportTag); |
| 14104 | + } |
| 14105 | + } else { // mobile mode with a viewport tag |
| 14106 | + // fix an edge case where WebView forces the wide viewport |
| 14107 | + const widthPart = parsedViewportContent.find(([key]) => key === 'width'); |
| 14108 | + const initialScalePart = parsedViewportContent.find(([key]) => key === 'initial-scale'); |
| 14109 | + if (!widthPart && initialScalePart) { |
| 14110 | + // Chromium accepts float values for initial-scale |
| 14111 | + const parsedInitialScale = parseFloat(initialScalePart[1]); |
| 14112 | + if (parsedInitialScale !== 1) { |
| 14113 | + viewportTag.setAttribute('content', `width=device-width, ${viewportContent}`); |
| 14114 | + } |
| 14115 | + } |
| 14116 | + } |
14080 | 14117 | } |
14081 | 14118 | } |
14082 | 14119 |
|
|
0 commit comments