From 7726cd762a0f1a89b89441c1434668f89ca76c2d Mon Sep 17 00:00:00 2001 From: Kyle Hickinson Date: Thu, 4 Jun 2026 20:53:52 -0400 Subject: [PATCH] [iOS] Opt-in to prettier for iOS typescript/markdown (#36998) --- .prettierignore | 3 +- .../ai_chat/resources/ai_chat_distiller.ts | 102 +++-- .../resources/ads_media_reporting.ts | 40 +- .../resources/brave_search_ad_results.ts | 68 +-- .../brave_search_make_default_helper.ts | 19 +- .../resources/brave_talk_launcher.ts | 18 +- ios/browser/favicon/docs.md | 26 +- .../global_privacy_control/resources/gpc.ts | 2 +- ios/browser/web/de_amp/resources/de_amp.ts | 58 +-- .../resources/document_fetch.ts | 40 +- .../web/force_paste/resources/force_paste.ts | 35 +- ios/browser/web/logins/resources/logins.ts | 395 +++++++++--------- .../media/resources/media_backgrounding.ts | 153 ++++--- .../navigator/resources/brave_navigator.ts | 6 +- .../page_metadata/resources/page_metadata.ts | 37 +- .../resources/brave_reader_mode.ts | 234 ++++++----- .../youtube/resources/yt_video_quality.ts | 15 +- .../yt_video_quality_event_listeners.ts | 15 +- .../resources/yt_video_quality_utils.ts | 39 +- .../message_handler_token_test_api.ts | 21 +- .../randomized_message_handler_test_api.ts | 17 +- .../js_messaging/resources/safe_builtins.ts | 114 +++-- ios/web/js_messaging/resources/utils.ts | 27 +- 23 files changed, 824 insertions(+), 660 deletions(-) diff --git a/.prettierignore b/.prettierignore index 92ae5b6aec2..3d63dd2e6bf 100644 --- a/.prettierignore +++ b/.prettierignore @@ -11,7 +11,7 @@ /chromium_src/components/ /chromium_src/third_party/ /chromium_src/ui/ -/ios +/ios/brave-ios/ /resources /test /.storybook/ @@ -21,6 +21,7 @@ /third_party/ /third_party/boringtun/vendor/ /third_party/wasm/vendor/ +/ios/third_party/ # Ignore github .yml files: .github/**/*.yml diff --git a/ios/browser/ai_chat/resources/ai_chat_distiller.ts b/ios/browser/ai_chat/resources/ai_chat_distiller.ts index 82c52795a65..1294bfcdea3 100644 --- a/ios/browser/ai_chat/resources/ai_chat_distiller.ts +++ b/ios/browser/ai_chat/resources/ai_chat_distiller.ts @@ -3,74 +3,100 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {CrWebApi, gCrWeb} from - '//ios/web/public/js_messaging/resources/gcrweb.js'; +import { + CrWebApi, + gCrWeb, +} from '//ios/web/public/js_messaging/resources/gcrweb.js' const kRolesToSkip: string[] = [ - 'audio', 'banner', 'button', 'complementary', - 'contentinfo', 'footer', 'img', 'label', 'navigation', - 'textbox', 'combobox', 'listbox', 'checkbox', 'radiobutton', - 'slider', 'spinbutton', 'searchbox', -]; + 'audio', + 'banner', + 'button', + 'complementary', + 'contentinfo', + 'footer', + 'img', + 'label', + 'navigation', + 'textbox', + 'combobox', + 'listbox', + 'checkbox', + 'radiobutton', + 'slider', + 'spinbutton', + 'searchbox', +] const kTagsToSkip: string[] = [ - 'AUDIO', 'HEADER', 'BUTTON', 'ASIDE', - 'FOOTER', 'IMG', 'PICTURE', 'LABEL', 'NAV', - 'INPUT', 'SEARCH', 'STYLE', -]; + 'AUDIO', + 'HEADER', + 'BUTTON', + 'ASIDE', + 'FOOTER', + 'IMG', + 'PICTURE', + 'LABEL', + 'NAV', + 'INPUT', + 'SEARCH', + 'STYLE', +] // Walk the node tree to find
and
tags and return them. function getRootNodes(): Node[] { - const result: Node[] = []; - const queue: Node[] = [document.documentElement]; + const result: Node[] = [] + const queue: Node[] = [document.documentElement] while (queue.length !== 0) { - const node = queue.pop()!; - const el = node as HTMLElement; - if ((el.role === 'main' || node.nodeName === 'MAIN') || - (el.role === 'article' || node.nodeName === 'ARTICLE')) { - result.push(node); - continue; + const node = queue.pop()! + const el = node as HTMLElement + if ( + el.role === 'main' + || node.nodeName === 'MAIN' + || el.role === 'article' + || node.nodeName === 'ARTICLE' + ) { + result.push(node) + continue } for (const child of node.childNodes) { - queue.push(child); + queue.push(child) } } - return result; + return result } // Recursively collect text from root, skipping unwanted roles and tags. function collectText(root: Node, out: string[]): void { - const queue: Node[] = [root]; + const queue: Node[] = [root] while (queue.length !== 0) { - const node = queue.pop()!; - const el = node as HTMLElement; + const node = queue.pop()! + const el = node as HTMLElement if (el.role && kRolesToSkip.includes(el.role)) { - continue; + continue } if (kTagsToSkip.includes(node.nodeName)) { - continue; + continue } if (node.nodeType === Node.TEXT_NODE) { - out.push((node as Text).wholeText); + out.push((node as Text).wholeText) } for (const child of node.childNodes) { - queue.push(child); + queue.push(child) } } } function getMainArticle(): string { - const rootNodes = getRootNodes(); - const textParts: string[] = []; + const rootNodes = getRootNodes() + const textParts: string[] = [] for (const node of rootNodes) { - collectText(node, textParts); + collectText(node, textParts) } - const text = textParts.join(' '); - return text.length !== 0 ? - text : - (document.body ? document.body.innerText : ''); + const text = textParts.join(' ') + return text.length !== 0 ? text : document.body ? document.body.innerText : '' } -const aiChatDistillerApi = new CrWebApi('aiChatDistiller'); -aiChatDistillerApi.addFunction('getMainArticle', getMainArticle); -gCrWeb.registerApi(aiChatDistillerApi); +const aiChatDistillerApi = new CrWebApi('aiChatDistiller') +aiChatDistillerApi.addFunction('getMainArticle', getMainArticle) +gCrWeb.registerApi(aiChatDistillerApi) diff --git a/ios/browser/brave_ads/resources/ads_media_reporting.ts b/ios/browser/brave_ads/resources/ads_media_reporting.ts index e36f89a614b..4894aa15ea6 100644 --- a/ios/browser/brave_ads/resources/ads_media_reporting.ts +++ b/ios/browser/brave_ads/resources/ads_media_reporting.ts @@ -3,35 +3,43 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {sendWebKitMessage} from '//ios/web/public/js_messaging/resources/utils.js'; +import { sendWebKitMessage } from '//ios/web/public/js_messaging/resources/utils.js' function sendMessage(playing: boolean) { - sendWebKitMessage('AdsMediaReportingMessageHandler', {'isPlaying': playing}); + sendWebKitMessage('AdsMediaReportingMessageHandler', { 'isPlaying': playing }) } function isPlayingVideoWithAudio(video: HTMLVideoElement): boolean { - return !video.paused && !video.muted; + return !video.paused && !video.muted } function hookVideoElement(video: HTMLVideoElement) { - video.addEventListener('pause', () => sendMessage(false), false); - video.addEventListener('playing', () => sendMessage(isPlayingVideoWithAudio(video)), false); - video.addEventListener('volumechange', () => sendMessage(isPlayingVideoWithAudio(video)), false); + video.addEventListener('pause', () => sendMessage(false), false) + video.addEventListener( + 'playing', + () => sendMessage(isPlayingVideoWithAudio(video)), + false, + ) + video.addEventListener( + 'volumechange', + () => sendMessage(isPlayingVideoWithAudio(video)), + false, + ) } -document.querySelectorAll('video').forEach(hookVideoElement); +document.querySelectorAll('video').forEach(hookVideoElement) -const observer = new MutationObserver(function(mutations: MutationRecord[]) { - mutations.forEach(function(mutation: MutationRecord) { - mutation.addedNodes.forEach(function(node: Node) { +const observer = new MutationObserver(function (mutations: MutationRecord[]) { + mutations.forEach(function (mutation: MutationRecord) { + mutation.addedNodes.forEach(function (node: Node) { if (node instanceof HTMLVideoElement) { - hookVideoElement(node); + hookVideoElement(node) } else if (node instanceof HTMLElement) { // Some sites inject a container element that already has video // descendants, so the video itself is never a direct added node. - node.querySelectorAll('video').forEach(hookVideoElement); + node.querySelectorAll('video').forEach(hookVideoElement) } - }); - }); -}); -observer.observe(document, {subtree: true, childList: true}); + }) + }) +}) +observer.observe(document, { subtree: true, childList: true }) diff --git a/ios/browser/brave_search/resources/brave_search_ad_results.ts b/ios/browser/brave_search/resources/brave_search_ad_results.ts index 38e168e5ed5..e00da8c783f 100644 --- a/ios/browser/brave_search/resources/brave_search_ad_results.ts +++ b/ios/browser/brave_search/resources/brave_search_ad_results.ts @@ -3,21 +3,24 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {CrWebApi, gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js'; +import { + CrWebApi, + gCrWeb, +} from '//ios/web/public/js_messaging/resources/gcrweb.js' interface Creative { - creativeInstanceId?: string; - placementId?: string; - creativeSetId?: string; - campaignId?: string; - advertiserId?: string; - landingPage?: string; - headlineText?: string; - description?: string; - rewardsValue?: string; - conversionUrlPatternValue?: string; - conversionAdvertiserPublicKeyValue?: string; - conversionObservationWindowValue?: string; + creativeInstanceId?: string + placementId?: string + creativeSetId?: string + campaignId?: string + advertiserId?: string + landingPage?: string + headlineText?: string + description?: string + rewardsValue?: string + conversionUrlPatternValue?: string + conversionAdvertiserPublicKeyValue?: string + conversionObservationWindowValue?: string } const creativeFieldNamesMapping: Record = { @@ -35,37 +38,38 @@ const creativeFieldNamesMapping: Record = { 'conversionAdvertiserPublicKeyValue', 'data-conversion-observation-window-value': 'conversionObservationWindowValue', -}; +} function getCreatives(): string { - const creatives: Creative[] = []; - const scripts = - document.querySelectorAll('script[type="application/ld+json"]'); + const creatives: Creative[] = [] + const scripts = document.querySelectorAll( + 'script[type="application/ld+json"]', + ) try { - const jsonLdList = - Array.from(scripts).map(script => JSON.parse(script.textContent || '')); + const jsonLdList = Array.from(scripts).map((script) => + JSON.parse(script.textContent || ''), + ) - jsonLdList.forEach(jsonLd => { + jsonLdList.forEach((jsonLd) => { if (jsonLd['@type'] === 'Product' && jsonLd.creatives) { jsonLd.creatives.forEach((creative: Record) => { if (creative['@type'] === 'SearchResultAd') { - const mapped: Creative = {}; + const mapped: Creative = {} for (const key in creative) { - const mappedKey = creativeFieldNamesMapping[key]; + const mappedKey = creativeFieldNamesMapping[key] if (mappedKey) { - mapped[mappedKey] = creative[key]; + mapped[mappedKey] = creative[key] } } - creatives.push(mapped); + creatives.push(mapped) } - }); + }) } - }); - } catch { - } - return JSON.stringify(creatives); + }) + } catch {} + return JSON.stringify(creatives) } -const braveSearchAdResultsApi = new CrWebApi('braveSearchAdResults'); -braveSearchAdResultsApi.addFunction('getCreatives', getCreatives); -gCrWeb.registerApi(braveSearchAdResultsApi); +const braveSearchAdResultsApi = new CrWebApi('braveSearchAdResults') +braveSearchAdResultsApi.addFunction('getCreatives', getCreatives) +gCrWeb.registerApi(braveSearchAdResultsApi) diff --git a/ios/browser/brave_search/resources/brave_search_make_default_helper.ts b/ios/browser/brave_search/resources/brave_search_make_default_helper.ts index aa7124acd31..8cad6627715 100644 --- a/ios/browser/brave_search/resources/brave_search_make_default_helper.ts +++ b/ios/browser/brave_search/resources/brave_search_make_default_helper.ts @@ -3,8 +3,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {sendWebKitMessageWithReply} from - '//ios/web/public/js_messaging/resources/utils.js'; +import { sendWebKitMessageWithReply } from '//ios/web/public/js_messaging/resources/utils.js' const allowedOrigins = [ 'https://safesearch.brave.com', @@ -14,7 +13,7 @@ const allowedOrigins = [ 'https://search.brave.com', 'https://search.brave.software', 'https://search.bravesoftware.com', -]; +] if (allowedOrigins.includes(window.location.origin)) { Object.defineProperty(window, 'brave', { @@ -24,13 +23,17 @@ if (allowedOrigins.includes(window.location.origin)) { value: { getCanSetDefaultSearchProvider() { return sendWebKitMessageWithReply( - 'BraveSearchMakeDefaultMessageHandler', {method_id: 1}); + 'BraveSearchMakeDefaultMessageHandler', + { method_id: 1 }, + ) }, setIsDefaultSearchProvider() { return sendWebKitMessageWithReply( - 'BraveSearchMakeDefaultMessageHandler', {method_id: 2}); - } - } - }); + 'BraveSearchMakeDefaultMessageHandler', + { method_id: 2 }, + ) + }, + }, + }) } diff --git a/ios/browser/brave_talk/resources/brave_talk_launcher.ts b/ios/browser/brave_talk/resources/brave_talk_launcher.ts index dd2718dc886..caf06e1bc8a 100644 --- a/ios/browser/brave_talk/resources/brave_talk_launcher.ts +++ b/ios/browser/brave_talk/resources/brave_talk_launcher.ts @@ -3,28 +3,28 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {sendWebKitMessage} from - '//ios/web/public/js_messaging/resources/utils.js'; +import { sendWebKitMessage } from '//ios/web/public/js_messaging/resources/utils.js' const allowedOrigins = [ 'https://talk.brave.com', 'https://talk.bravesoftware.com', 'https://talk.brave.software', -]; +] if (allowedOrigins.includes(window.location.origin)) { const observer = new MutationObserver((mutations: MutationRecord[]) => { for (const mutation of mutations) { for (const node of mutation.addedNodes) { if (node instanceof HTMLIFrameElement) { - sendWebKitMessage( - 'BraveTalkLauncherMessageHandler', {url: node.src}); - observer.disconnect(); - return; + sendWebKitMessage('BraveTalkLauncherMessageHandler', { + url: node.src, + }) + observer.disconnect() + return } } } - }); + }) - observer.observe(document, {childList: true, subtree: true}); + observer.observe(document, { childList: true, subtree: true }) } diff --git a/ios/browser/favicon/docs.md b/ios/browser/favicon/docs.md index ccd9ed2b5ab..444edc57994 100644 --- a/ios/browser/favicon/docs.md +++ b/ios/browser/favicon/docs.md @@ -1,15 +1,22 @@ # Favicon Documentation -This file documents the list of changes made to the Chromium iOS Favicon implementation as it isn't compatible with Brave-iOS. - +This file documents the list of changes made to the Chromium iOS Favicon +implementation as it isn't compatible with Brave-iOS. # Changes -[BraveIOSWebFaviconDriver.h](https://github.com/brave/brave-core/blob/master/ios/browser/favicon/brave_ios_web_favicon_driver.h): Modification of `WebFaviconDriver` to get rid of `web::WebState` and instead use `ProfileIOS` as iOS cannot use `web::WebState` since we do not use `CRWWebView` in our Swift code. This means we got rid of all the `WebStateObserver` and `UserData` as well, and instead store the class with the `ProfileIOS`. This is done via the `CreateForBrowserState` and `FromBrowserState` functions. +[BraveIOSWebFaviconDriver.h](https://github.com/brave/brave-core/blob/master/ios/browser/favicon/brave_ios_web_favicon_driver.h): +Modification of `WebFaviconDriver` to get rid of `web::WebState` and instead use +`ProfileIOS` as iOS cannot use `web::WebState` since we do not use `CRWWebView` +in our Swift code. This means we got rid of all the `WebStateObserver` and +`UserData` as well, and instead store the class with the `ProfileIOS`. This is +done via the `CreateForBrowserState` and `FromBrowserState` functions. [BraveIOSWebFaviconDriver.mm](https://github.com/brave/brave-core/blob/master/ios/browser/favicon/brave_ios_web_favicon_driver.mm) -The below code was added in order to setup a navigation stack for the Swift iOS WebView when navigation has just begun. +The below code was added in order to setup a navigation stack for the Swift iOS +WebView when navigation has just begun. + ```c++ void BraveIOSWebFaviconDriver::DidStartNavigation( ProfileIOS* profile, @@ -22,17 +29,22 @@ void BraveIOSWebFaviconDriver::DidStartNavigation( } ``` -When navigation is complete, we call the below function to begin fetching the `Favicon` for the `URL` that was navigated to: +When navigation is complete, we call the below function to begin fetching the +`Favicon` for the `URL` that was navigated to: + ```c++ void BraveIOSWebFaviconDriver::DidFinishNavigation( ProfileIOS* profile, const GURL& page_url) { web::NavigationItemImpl* item = !items.empty() ? items.back().get() : nullptr; DCHECK(item); - + // Fetch the fav-icon FetchFavicon(item->GetURL(), /*IsSameDocument*/ **false**); } ``` -This all emulates the `web::WebState::DidStartNavigation` and `web::WebState::DidFinishNavigation` functions in a much simpler way, that would be compatible with Brave-iOS until the day we switch over to using Chromium's `CRWWebView`. \ No newline at end of file +This all emulates the `web::WebState::DidStartNavigation` and +`web::WebState::DidFinishNavigation` functions in a much simpler way, that would +be compatible with Brave-iOS until the day we switch over to using Chromium's +`CRWWebView`. diff --git a/ios/browser/global_privacy_control/resources/gpc.ts b/ios/browser/global_privacy_control/resources/gpc.ts index 78ea99c2f35..bf4938d1af5 100644 --- a/ios/browser/global_privacy_control/resources/gpc.ts +++ b/ios/browser/global_privacy_control/resources/gpc.ts @@ -7,5 +7,5 @@ Object.defineProperty(navigator, 'globalPrivacyControl', { enumerable: false, configurable: false, writable: false, - value: (window as any).gCrWebPlaceholderGPCEnabled + value: (window as any).gCrWebPlaceholderGPCEnabled, }) diff --git a/ios/browser/web/de_amp/resources/de_amp.ts b/ios/browser/web/de_amp/resources/de_amp.ts index ca04265df20..71a2ca5a427 100644 --- a/ios/browser/web/de_amp/resources/de_amp.ts +++ b/ios/browser/web/de_amp/resources/de_amp.ts @@ -3,55 +3,59 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {sendWebKitMessageWithReply} from '//ios/web/public/js_messaging/resources/utils.js'; +import { sendWebKitMessageWithReply } from '//ios/web/public/js_messaging/resources/utils.js' -let timesToCheck = 20; -let intervalId = 0; +let timesToCheck = 20 +let intervalId = 0 function checkForAmp(): void { - const htmlElm = document.documentElement; - const headElm = document.head; + const htmlElm = document.documentElement + const headElm = document.head if (!headElm && !htmlElm) { if (--timesToCheck === 0) { - window.clearInterval(intervalId); + window.clearInterval(intervalId) } - return; + return } if (!htmlElm.hasAttribute('amp') && !htmlElm.hasAttribute('⚡')) { - window.clearInterval(intervalId); - return; + window.clearInterval(intervalId) + return } - const canonicalLinkElm = - document.querySelector('head > link[rel="canonical"][href^="http"]'); + const canonicalLinkElm = document.querySelector( + 'head > link[rel="canonical"][href^="http"]', + ) if (!canonicalLinkElm) { if (--timesToCheck === 0) { - window.clearInterval(intervalId); + window.clearInterval(intervalId) } - return; + return } try { - const destUrl = new URL(canonicalLinkElm.getAttribute('href')!); - window.clearInterval(intervalId); + const destUrl = new URL(canonicalLinkElm.getAttribute('href')!) + window.clearInterval(intervalId) - if (window.location.href === destUrl.href || - !(destUrl.protocol === 'http:' || destUrl.protocol === 'https:')) { - return; + if ( + window.location.href === destUrl.href + || !(destUrl.protocol === 'http:' || destUrl.protocol === 'https:') + ) { + return } - sendWebKitMessageWithReply('DeAmpMessageHandler', {destURL: destUrl.href}) - .then((shouldRedirect: boolean) => { - if (shouldRedirect) { - window.location.replace(destUrl.href); - } - }); + sendWebKitMessageWithReply('DeAmpMessageHandler', { + destURL: destUrl.href, + }).then((shouldRedirect: boolean) => { + if (shouldRedirect) { + window.location.replace(destUrl.href) + } + }) } catch (_) { - window.clearInterval(intervalId); + window.clearInterval(intervalId) } } -intervalId = window.setInterval(checkForAmp, 250); -checkForAmp(); +intervalId = window.setInterval(checkForAmp, 250) +checkForAmp() diff --git a/ios/browser/web/document_fetch/resources/document_fetch.ts b/ios/browser/web/document_fetch/resources/document_fetch.ts index f9dcba7f485..4eeee262cec 100644 --- a/ios/browser/web/document_fetch/resources/document_fetch.ts +++ b/ios/browser/web/document_fetch/resources/document_fetch.ts @@ -3,37 +3,39 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {CrWebApi, gCrWeb} - from '//ios/web/public/js_messaging/resources/gcrweb.js'; -import {sendWebKitMessage} - from '//ios/web/public/js_messaging/resources/utils.js'; +import { + CrWebApi, + gCrWeb, +} from '//ios/web/public/js_messaging/resources/gcrweb.js' +import { sendWebKitMessage } from '//ios/web/public/js_messaging/resources/utils.js' function download(url: string): void { - const xhr = new XMLHttpRequest(); - xhr.responseType = 'arraybuffer'; - xhr.onreadystatechange = function() { + const xhr = new XMLHttpRequest() + xhr.responseType = 'arraybuffer' + xhr.onreadystatechange = function () { if (this.readyState !== XMLHttpRequest.DONE) { - return; + return } if (this.status === 200) { - const byteArray = new Uint8Array(this.response as ArrayBuffer); - const binaryString = - Array.from(byteArray).map(b => String.fromCharCode(b)).join(''); + const byteArray = new Uint8Array(this.response as ArrayBuffer) + const binaryString = Array.from(byteArray) + .map((b) => String.fromCharCode(b)) + .join('') sendWebKitMessage('DocumentFetchMessageHandler', { statusCode: this.status, base64Data: window.btoa(binaryString), - }); + }) } else { sendWebKitMessage('DocumentFetchMessageHandler', { statusCode: this.status, base64Data: '', - }); + }) } - }; - xhr.open('GET', url, true); - xhr.send(null); + } + xhr.open('GET', url, true) + xhr.send(null) } -const documentFetchApi = new CrWebApi('documentFetch'); -documentFetchApi.addFunction('download', download); -gCrWeb.registerApi(documentFetchApi); +const documentFetchApi = new CrWebApi('documentFetch') +documentFetchApi.addFunction('download', download) +gCrWeb.registerApi(documentFetchApi) diff --git a/ios/browser/web/force_paste/resources/force_paste.ts b/ios/browser/web/force_paste/resources/force_paste.ts index a1180953e9c..f8b69f4a5ef 100644 --- a/ios/browser/web/force_paste/resources/force_paste.ts +++ b/ios/browser/web/force_paste/resources/force_paste.ts @@ -3,32 +3,37 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {CrWebApi, gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js'; +import { + CrWebApi, + gCrWeb, +} from '//ios/web/public/js_messaging/resources/gcrweb.js' function pasteIntoActiveElement(contents: string) { - let element: Element | null = document.activeElement; + let element: Element | null = document.activeElement while (element?.tagName === 'IFRAME') { // If the element is an iframe, recurse into it to find the active element - element = (element as HTMLIFrameElement).contentDocument?.activeElement ?? null; + element = + (element as HTMLIFrameElement).contentDocument?.activeElement ?? null } if (element === null) { - return; + return } if (!(element.tagName === 'INPUT' || element.tagName === 'TEXTAREA')) { - return; + return } - const inputElement = element as HTMLInputElement | HTMLTextAreaElement; - const start = inputElement.selectionStart ?? 0; + const inputElement = element as HTMLInputElement | HTMLTextAreaElement + const start = inputElement.selectionStart ?? 0 // Paste into expected position, replacing contents if any are selected inputElement.value = - inputElement.value.slice(0, start) + contents + - inputElement.value.slice(inputElement.selectionEnd ?? start); + inputElement.value.slice(0, start) + + contents + + inputElement.value.slice(inputElement.selectionEnd ?? start) // Reset caret position to expected position - const newSelection = start + contents.length; - inputElement.selectionStart = newSelection; - inputElement.selectionEnd = newSelection; + const newSelection = start + contents.length + inputElement.selectionStart = newSelection + inputElement.selectionEnd = newSelection } -const forcePasteApi = new CrWebApi('forcePaste'); -forcePasteApi.addFunction('pasteIntoActiveElement', pasteIntoActiveElement); -gCrWeb.registerApi(forcePasteApi); +const forcePasteApi = new CrWebApi('forcePaste') +forcePasteApi.addFunction('pasteIntoActiveElement', pasteIntoActiveElement) +gCrWeb.registerApi(forcePasteApi) diff --git a/ios/browser/web/logins/resources/logins.ts b/ios/browser/web/logins/resources/logins.ts index 7afac790eb1..2ab339110a2 100644 --- a/ios/browser/web/logins/resources/logins.ts +++ b/ios/browser/web/logins/resources/logins.ts @@ -6,79 +6,86 @@ import { sendWebKitMessage, sendWebKitMessageWithReply, -} from '//ios/web/public/js_messaging/resources/utils.js'; +} from '//ios/web/public/js_messaging/resources/utils.js' -const HANDLER_NAME = 'LoginsMessageHandler'; +const HANDLER_NAME = 'LoginsMessageHandler' -const KEYCODE_ARROW_DOWN = 40; +const KEYCODE_ARROW_DOWN = 40 -let gEnabled = true; -let gStoreWhenAutocompleteOff = true; -let gAutofillForms = true; +let gEnabled = true +let gStoreWhenAutocompleteOff = true +let gAutofillForms = true interface LoginData { - hostname: string; - formSubmitURL: string; - httpRealm: string; - username: string; - password: string; - usernameField: string; - passwordField: string; + hostname: string + formSubmitURL: string + httpRealm: string + username: string + password: string + usernameField: string + passwordField: string } function isUsernameFieldType(element: Element): boolean { if (!(element instanceof HTMLInputElement)) { - return false; + return false } - const fieldType = element.hasAttribute('type') ? - element.getAttribute('type')!.toLowerCase() : - element.type; - return fieldType === 'text' || fieldType === 'email' || - fieldType === 'url' || fieldType === 'tel' || - fieldType === 'number'; + const fieldType = element.hasAttribute('type') + ? element.getAttribute('type')!.toLowerCase() + : element.type + return ( + fieldType === 'text' + || fieldType === 'email' + || fieldType === 'url' + || fieldType === 'tel' + || fieldType === 'number' + ) } function isAutocompleteDisabled(element: Element | null): boolean { - if (element && element.hasAttribute('autocomplete') && - element.getAttribute('autocomplete')!.toLowerCase() === 'off') { - return true; + if ( + element + && element.hasAttribute('autocomplete') + && element.getAttribute('autocomplete')!.toLowerCase() === 'off' + ) { + return true } - return false; + return false } interface PasswordFieldEntry { - index: number; - element: HTMLInputElement; + index: number + element: HTMLInputElement } function getPasswordFields( - form: HTMLFormElement, - skipEmpty: boolean): PasswordFieldEntry[] | null { - const pwFields: PasswordFieldEntry[] = []; + form: HTMLFormElement, + skipEmpty: boolean, +): PasswordFieldEntry[] | null { + const pwFields: PasswordFieldEntry[] = [] for (let i = 0; i < form.elements.length; i++) { - const element = form.elements[i]; - if (!(element instanceof HTMLInputElement) || - element.type !== 'password') { - continue; + const element = form.elements[i] + if (!(element instanceof HTMLInputElement) || element.type !== 'password') { + continue } if (skipEmpty && !element.value) { - continue; + continue } - pwFields.push({index: i, element}); + pwFields.push({ index: i, element }) } if (pwFields.length === 0 || pwFields.length > 3) { - return null; + return null } - return pwFields; + return pwFields } function getFormFields( - form: HTMLFormElement, - isSubmission: boolean): [HTMLInputElement | null, HTMLInputElement | null, - HTMLInputElement | null] { - const pwFields = getPasswordFields(form, isSubmission); + form: HTMLFormElement, + isSubmission: boolean, +): [HTMLInputElement | null, HTMLInputElement | null, HTMLInputElement | null] { + const pwFields = getPasswordFields(form, isSubmission) if (!pwFields) { - return [null, null, null]; + return [null, null, null] } // getPasswordFields guarantees at least one entry; destructure for safe @@ -87,248 +94,260 @@ function getFormFields( PasswordFieldEntry, PasswordFieldEntry | undefined, PasswordFieldEntry | undefined, - ]; + ] - let usernameField: HTMLInputElement | null = null; + let usernameField: HTMLInputElement | null = null for (let i = pw0.index - 1; i >= 0; i--) { - const element = form.elements[i]; + const element = form.elements[i] if (isUsernameFieldType(element as Element)) { - usernameField = element as HTMLInputElement; - break; + usernameField = element as HTMLInputElement + break } } if (!isSubmission || pwFields.length === 1) { - return [usernameField, pw0.element, null]; + return [usernameField, pw0.element, null] } - const val0 = pw0.element.value; - const val1 = pw1!.element.value; - const val2 = pw2 ? pw2.element.value : null; + const val0 = pw0.element.value + const val1 = pw1!.element.value + const val2 = pw2 ? pw2.element.value : null - let oldPasswordField: HTMLInputElement | null; - let newPasswordField: HTMLInputElement; + let oldPasswordField: HTMLInputElement | null + let newPasswordField: HTMLInputElement if (pwFields.length === 3) { if (val0 === val1 && val1 === val2) { - newPasswordField = pw0.element; - oldPasswordField = null; + newPasswordField = pw0.element + oldPasswordField = null } else if (val0 === val1) { - newPasswordField = pw0.element; - oldPasswordField = pw2!.element; + newPasswordField = pw0.element + oldPasswordField = pw2!.element } else if (val1 === val2) { - oldPasswordField = pw0.element; - newPasswordField = pw2!.element; + oldPasswordField = pw0.element + newPasswordField = pw2!.element } else if (val0 === val2) { - newPasswordField = pw0.element; - oldPasswordField = pw1!.element; + newPasswordField = pw0.element + oldPasswordField = pw1!.element } else { - return [null, null, null]; + return [null, null, null] } } else { if (val0 === val1) { - newPasswordField = pw0.element; - oldPasswordField = null; + newPasswordField = pw0.element + oldPasswordField = null } else { - oldPasswordField = pw0.element; - newPasswordField = pw1!.element; + oldPasswordField = pw0.element + newPasswordField = pw1!.element } } - return [usernameField, newPasswordField, oldPasswordField]; + return [usernameField, newPasswordField, oldPasswordField] } function dispatchKeyboardEvent( - element: HTMLElement, eventName: string, keyCode: number): void { + element: HTMLElement, + eventName: string, + keyCode: number, +): void { element.dispatchEvent( - new KeyboardEvent(eventName, {bubbles: true, cancelable: true, keyCode})); + new KeyboardEvent(eventName, { bubbles: true, cancelable: true, keyCode }), + ) } function fillForm( - form: HTMLFormElement, - autofillForm: boolean, - ignoreAutocomplete: boolean, - clobberPassword: boolean, - userTriggered: boolean, - foundLogins: LoginData[]): [boolean, LoginData[]] { - const [usernameField, passwordField] = getFormFields(form, false); + form: HTMLFormElement, + autofillForm: boolean, + ignoreAutocomplete: boolean, + clobberPassword: boolean, + userTriggered: boolean, + foundLogins: LoginData[], +): [boolean, LoginData[]] { + const [usernameField, passwordField] = getFormFields(form, false) if (!passwordField) { - return [false, foundLogins]; + return [false, foundLogins] } if (passwordField.disabled || passwordField.readOnly) { - return [false, foundLogins]; + return [false, foundLogins] } - let maxUsernameLen = Number.MAX_VALUE; - let maxPasswordLen = Number.MAX_VALUE; + let maxUsernameLen = Number.MAX_VALUE + let maxPasswordLen = Number.MAX_VALUE if (usernameField && usernameField.maxLength >= 0) { - maxUsernameLen = usernameField.maxLength; + maxUsernameLen = usernameField.maxLength } if (passwordField.maxLength >= 0) { - maxPasswordLen = passwordField.maxLength; + maxPasswordLen = passwordField.maxLength } const logins = foundLogins.filter( - l => l.username.length <= maxUsernameLen && - l.password.length <= maxPasswordLen); + (l) => + l.username.length <= maxUsernameLen + && l.password.length <= maxPasswordLen, + ) if (logins.length === 0) { - return [false, foundLogins]; + return [false, foundLogins] } // Don't clobber an existing password. if (passwordField.value && !clobberPassword) { - return [false, foundLogins]; + return [false, foundLogins] } - let selectedLogin: LoginData | null = null; + let selectedLogin: LoginData | null = null - if (usernameField && - (usernameField.value || usernameField.disabled || - usernameField.readOnly)) { - const username = usernameField.value.toLowerCase(); - const matchingLogins = - logins.filter(l => l.username.toLowerCase() === username); + if ( + usernameField + && (usernameField.value || usernameField.disabled || usernameField.readOnly) + ) { + const username = usernameField.value.toLowerCase() + const matchingLogins = logins.filter( + (l) => l.username.toLowerCase() === username, + ) if (matchingLogins.length) { for (const l of matchingLogins) { if (l.username === usernameField.value) { - selectedLogin = l; - break; + selectedLogin = l + break } } if (!selectedLogin) { - selectedLogin = matchingLogins[0] ?? null; + selectedLogin = matchingLogins[0] ?? null } } } else if (logins.length === 1) { - selectedLogin = logins[0] ?? null; + selectedLogin = logins[0] ?? null } else { - const matchingLogins = usernameField ? - logins.filter(l => l.username) : - logins.filter(l => !l.username); - selectedLogin = matchingLogins[0] ?? null; + const matchingLogins = usernameField + ? logins.filter((l) => l.username) + : logins.filter((l) => !l.username) + selectedLogin = matchingLogins[0] ?? null } - let isFormDisabled = false; - if (!ignoreAutocomplete && - (isAutocompleteDisabled(form) || - isAutocompleteDisabled(usernameField) || - isAutocompleteDisabled(passwordField))) { - isFormDisabled = true; + let isFormDisabled = false + if ( + !ignoreAutocomplete + && (isAutocompleteDisabled(form) + || isAutocompleteDisabled(usernameField) + || isAutocompleteDisabled(passwordField)) + ) { + isFormDisabled = true } if (selectedLogin && autofillForm && !isFormDisabled) { if (usernameField) { const disabledOrReadOnly = - usernameField.disabled || usernameField.readOnly; - const userNameDiffers = - selectedLogin.username !== usernameField.value; - const userEnteredDifferentCase = userTriggered && userNameDiffers && - usernameField.value.toLowerCase() === - selectedLogin.username.toLowerCase(); + usernameField.disabled || usernameField.readOnly + const userNameDiffers = selectedLogin.username !== usernameField.value + const userEnteredDifferentCase = + userTriggered + && userNameDiffers + && usernameField.value.toLowerCase() + === selectedLogin.username.toLowerCase() - if (!disabledOrReadOnly && !userEnteredDifferentCase && - userNameDiffers) { - usernameField.value = selectedLogin.username; + if (!disabledOrReadOnly && !userEnteredDifferentCase && userNameDiffers) { + usernameField.value = selectedLogin.username if (document.activeElement !== usernameField) { - usernameField.dispatchEvent(new Event('change')); + usernameField.dispatchEvent(new Event('change')) } - dispatchKeyboardEvent(usernameField, 'keydown', KEYCODE_ARROW_DOWN); - dispatchKeyboardEvent(usernameField, 'keyup', KEYCODE_ARROW_DOWN); + dispatchKeyboardEvent(usernameField, 'keydown', KEYCODE_ARROW_DOWN) + dispatchKeyboardEvent(usernameField, 'keyup', KEYCODE_ARROW_DOWN) } } if (passwordField.value !== selectedLogin.password) { - passwordField.value = selectedLogin.password; + passwordField.value = selectedLogin.password if (document.activeElement !== passwordField) { - passwordField.dispatchEvent(new Event('change')); + passwordField.dispatchEvent(new Event('change')) } - dispatchKeyboardEvent(passwordField, 'keydown', KEYCODE_ARROW_DOWN); - dispatchKeyboardEvent(passwordField, 'keyup', KEYCODE_ARROW_DOWN); + dispatchKeyboardEvent(passwordField, 'keydown', KEYCODE_ARROW_DOWN) + dispatchKeyboardEvent(passwordField, 'keyup', KEYCODE_ARROW_DOWN) } - return [true, foundLogins]; + return [true, foundLogins] } - return [false, foundLogins]; + return [false, foundLogins] } -async function asyncFindLogins( - form: HTMLFormElement): Promise { - const fields = getFormFields(form, false); +async function asyncFindLogins(form: HTMLFormElement): Promise { + const fields = getFormFields(form, false) if (!fields[0] || !fields[1]) { - return []; + return [] } - fields[0].addEventListener('blur', onBlur); + fields[0].addEventListener('blur', onBlur) - const actionOrigin = form.action || form.baseURI; + const actionOrigin = form.action || form.baseURI if (!actionOrigin) { - return []; + return [] } try { const logins = await sendWebKitMessageWithReply(HANDLER_NAME, { type: 'request', actionOrigin, - }); - return Array.isArray(logins) ? (logins as LoginData[]) : []; + }) + return Array.isArray(logins) ? (logins as LoginData[]) : [] } catch (_) { - return []; + return [] } } async function onBlur(event: Event): Promise { if (!gEnabled) { - return; + return } - const acInputField = event.target as HTMLInputElement; + const acInputField = event.target as HTMLInputElement if (!(acInputField.ownerDocument instanceof HTMLDocument)) { - return; + return } if (!isUsernameFieldType(acInputField)) { - return; + return } - const acForm = acInputField.form; + const acForm = acInputField.form if (!acForm) { - return; + return } if (!acInputField.value) { - return; + return } - const [usernameField, passwordField] = getFormFields(acForm, false); + const [usernameField, passwordField] = getFormFields(acForm, false) if (usernameField === acInputField && passwordField) { - const logins = await asyncFindLogins(acForm); - fillForm(acForm, true, true, true, true, logins); + const logins = await asyncFindLogins(acForm) + fillForm(acForm, true, true, true, true, logins) } } function onFormSubmit(form: HTMLFormElement): void { if (!gEnabled) { - return; + return } - const hostname = document.documentURI; + const hostname = document.documentURI if (!hostname) { - return; + return } - const formSubmitURL = form.action || form.baseURI; - const fields = getFormFields(form, true); - const [usernameField, newPasswordField, oldPasswordField] = fields; + const formSubmitURL = form.action || form.baseURI + const fields = getFormFields(form, true) + const [usernameField, newPasswordField, oldPasswordField] = fields if (!newPasswordField) { - return; + return } - if ((isAutocompleteDisabled(form) || - isAutocompleteDisabled(usernameField) || - isAutocompleteDisabled(newPasswordField) || - isAutocompleteDisabled(oldPasswordField)) && - !gStoreWhenAutocompleteOff) { - return; + if ( + (isAutocompleteDisabled(form) + || isAutocompleteDisabled(usernameField) + || isAutocompleteDisabled(newPasswordField) + || isAutocompleteDisabled(oldPasswordField)) + && !gStoreWhenAutocompleteOff + ) { + return } sendWebKitMessage(HANDLER_NAME, { @@ -341,14 +360,14 @@ function onFormSubmit(form: HTMLFormElement): void { passwordField: newPasswordField.name, formSubmitURL, }), - }); + }) } async function findLogins(form: HTMLFormElement): Promise { try { - const logins = await asyncFindLogins(form); + const logins = await asyncFindLogins(form) if (logins.length > 0) { - fillForm(form, gAutofillForms, false, false, false, logins); + fillForm(form, gAutofillForms, false, false, false, logins) } } catch (_) { // Eat errors to avoid leaking them to the page @@ -357,23 +376,23 @@ async function findLogins(form: HTMLFormElement): Promise { function findForms(nodes: NodeList): void { for (let i = 0; i < nodes.length; i++) { - const node = nodes[i]; + const node = nodes[i] if (!node) { - continue; + continue } if ((node as Element).nodeName === 'FORM') { - findLogins(node as HTMLFormElement); + findLogins(node as HTMLFormElement) } else if (node.hasChildNodes()) { - findForms(node.childNodes); + findForms(node.childNodes) } } } -const observer = new MutationObserver(mutations => { +const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { - findForms(mutation.addedNodes); + findForms(mutation.addedNodes) } -}); +}) window.addEventListener('load', () => { observer.observe(document.body, { @@ -381,60 +400,60 @@ window.addEventListener('load', () => { childList: true, characterData: false, subtree: true, - }); + }) for (let i = 0; i < document.forms.length; i++) { - const form = document.forms[i]; + const form = document.forms[i] if (form) { - findLogins(form); + findLogins(form) } } -}); +}) -window.addEventListener('submit', event => { +window.addEventListener('submit', (event) => { try { for (let i = 0; i < document.forms.length; i++) { - const form = document.forms[i]; + const form = document.forms[i] if (form) { - findLogins(form); + findLogins(form) } } - onFormSubmit(event.target as HTMLFormElement); + onFormSubmit(event.target as HTMLFormElement) } catch (_) { // Eat errors to avoid leaking them to the page } -}); +}) -window.addEventListener('pagehide', event => { +window.addEventListener('pagehide', (event) => { if ((event as PageTransitionEvent).persisted) { - return; + return } const isSubmittedForm = (form: HTMLFormElement): boolean => { - const fields = getFormFields(form, false); + const fields = getFormFields(form, false) if (!fields[0] || !fields[1]) { - return false; + return false } - const actionOrigin = form.action || form.baseURI; + const actionOrigin = form.action || form.baseURI if (!actionOrigin) { - return false; + return false } for (const field of fields) { if (field && (!field.value || field.value.length === 0)) { - return false; + return false } } - return true; - }; + return true + } for (const form of document.forms) { if (isSubmittedForm(form)) { try { - onFormSubmit(form); + onFormSubmit(form) } catch (_) { // Eat errors to avoid leaking them to the page } } } -}); +}) diff --git a/ios/browser/web/media/resources/media_backgrounding.ts b/ios/browser/web/media/resources/media_backgrounding.ts index fa9f346cc58..d8c7d4d3b25 100644 --- a/ios/browser/web/media/resources/media_backgrounding.ts +++ b/ios/browser/web/media/resources/media_backgrounding.ts @@ -5,101 +5,122 @@ function enable(): void { const descriptor = Object.getOwnPropertyDescriptor( - Document.prototype, 'visibilityState' - )!; - const visibilityStateGet = descriptor.get!; + Document.prototype, + 'visibilityState', + )! + const visibilityStateGet = descriptor.get! Object.defineProperty(Document.prototype, 'visibilityState', { enumerable: descriptor.enumerable, configurable: descriptor.configurable, get() { - const result = visibilityStateGet.call(this); + const result = visibilityStateGet.call(this) if (result !== 'visible') { - return 'visible'; + return 'visible' } - return result; - } - }); + return result + }, + }) - const pauseControl = HTMLVideoElement.prototype.pause; - HTMLVideoElement.prototype.pause = function(): void { - (this as any).userHitPause = true; - pauseControl.call(this); - }; + const pauseControl = HTMLVideoElement.prototype.pause + HTMLVideoElement.prototype.pause = function (): void { + ;(this as any).userHitPause = true + pauseControl.call(this) + } - const playControl = HTMLVideoElement.prototype.play; - HTMLVideoElement.prototype.play = function(): Promise { - (this as any).userHitPause = false; - return playControl.call(this); - }; + const playControl = HTMLVideoElement.prototype.play + HTMLVideoElement.prototype.play = function (): Promise { + ;(this as any).userHitPause = false + return playControl.call(this) + } function addListeners(element: HTMLVideoElement): void { if (!(element as any).pauseListener) { - (element as any).pauseListener = true; - (element as any).visibilityState = visibilityStateGet.call(document); + ;(element as any).pauseListener = true + ;(element as any).visibilityState = visibilityStateGet.call(document) - document.addEventListener('visibilitychange', function() { - (element as any).visibilityState = visibilityStateGet.call(document); - }, false); + document.addEventListener( + 'visibilitychange', + function () { + ;(element as any).visibilityState = visibilityStateGet.call(document) + }, + false, + ) - element.addEventListener('pause', function() { - if (!(element as any).userHitPause && - visibilityStateGet.call(document) === 'visible') { - const onVisibilityChanged = () => { - document.removeEventListener( - 'visibilitychange', onVisibilityChanged - ); - if (visibilityStateGet.call(document) !== 'visible' && - !element.ended) { - playControl.call(element); + element.addEventListener( + 'pause', + function () { + if ( + !(element as any).userHitPause + && visibilityStateGet.call(document) === 'visible' + ) { + const onVisibilityChanged = () => { + document.removeEventListener( + 'visibilitychange', + onVisibilityChanged, + ) + if ( + visibilityStateGet.call(document) !== 'visible' + && !element.ended + ) { + playControl.call(element) + } + } + document.addEventListener('visibilitychange', onVisibilityChanged) + setTimeout(function () { + document.removeEventListener( + 'visibilitychange', + onVisibilityChanged, + ) + }, 2000) + } else { + if ( + !(element as any).userHitPause + && (element as any).visibilityState === 'visible' + && !element.ended + ) { + playControl.call(element) } - }; - document.addEventListener('visibilitychange', onVisibilityChanged); - setTimeout(function() { - document.removeEventListener( - 'visibilitychange', onVisibilityChanged - ); - }, 2000); - } else { - if (!(element as any).userHitPause && - (element as any).visibilityState === 'visible' && - !element.ended) { - playControl.call(element); } - } - }, false); + }, + false, + ) } if (!(element as any).presentationModeListener) { - (element as any).presentationModeListener = true; - element.addEventListener('webkitpresentationmodechanged', function(e) { - e.stopPropagation(); - }, true); + ;(element as any).presentationModeListener = true + element.addEventListener( + 'webkitpresentationmodechanged', + function (e) { + e.stopPropagation() + }, + true, + ) } } - const queue: MutationRecord[] = []; + const queue: MutationRecord[] = [] function onMutation(): void { for (const mutation of queue) { - mutation.addedNodes.forEach(function(node: Node) { + mutation.addedNodes.forEach(function (node: Node) { if (node instanceof HTMLVideoElement) { - addListeners(node); + addListeners(node) } - }); + }) } - queue.length = 0; + queue.length = 0 } - const observer = new MutationObserver(function(mutations: MutationRecord[]) { + const observer = new MutationObserver(function (mutations: MutationRecord[]) { if (!queue.length) { - requestAnimationFrame(onMutation); + requestAnimationFrame(onMutation) } - queue.push(...mutations); - }); + queue.push(...mutations) + }) - document.querySelectorAll('video').forEach( - (v) => addListeners(v as HTMLVideoElement) - ); + document + .querySelectorAll('video') + .forEach((v) => addListeners(v as HTMLVideoElement)) observer.observe(document, { childList: true, @@ -107,10 +128,10 @@ function enable(): void { characterData: false, subtree: true, attributeOldValue: false, - characterDataOldValue: false - }); + characterDataOldValue: false, + }) } if ((window as any).gCrWebPlaceholderMediaBackgroundingEnabled) { - enable(); + enable() } diff --git a/ios/browser/web/navigator/resources/brave_navigator.ts b/ios/browser/web/navigator/resources/brave_navigator.ts index d5143c34b28..5439d2e6cd4 100644 --- a/ios/browser/web/navigator/resources/brave_navigator.ts +++ b/ios/browser/web/navigator/resources/brave_navigator.ts @@ -8,6 +8,6 @@ Object.defineProperty(navigator, 'brave', { configurable: true, writable: false, value: Object.freeze({ - isBrave: (): Promise => Promise.resolve(true) - }) -}); + isBrave: (): Promise => Promise.resolve(true), + }), +}) diff --git a/ios/browser/web/page_metadata/resources/page_metadata.ts b/ios/browser/web/page_metadata/resources/page_metadata.ts index ff463f2ff8c..bb94ef1e644 100644 --- a/ios/browser/web/page_metadata/resources/page_metadata.ts +++ b/ios/browser/web/page_metadata/resources/page_metadata.ts @@ -3,28 +3,35 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {CrWebApi, gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js'; +import { + CrWebApi, + gCrWeb, +} from '//ios/web/public/js_messaging/resources/gcrweb.js' function getMetadata(): string { const searchEl = document.querySelector( - 'link[type="application/opensearchdescription+xml"]'); - const search = searchEl ? { - title: (searchEl as HTMLLinkElement).title, - href: (searchEl as HTMLLinkElement).href, - } : null; + 'link[type="application/opensearchdescription+xml"]', + ) + const search = searchEl + ? { + title: (searchEl as HTMLLinkElement).title, + href: (searchEl as HTMLLinkElement).href, + } + : null const feedNodes = document.querySelectorAll( - 'link[type="application/rss+xml"], ' + - 'link[type="application/atom+xml"], ' + - 'link[rel="alternate"][type="application/json"]'); - const feeds = Array.from(feedNodes).map(link => ({ + 'link[type="application/rss+xml"], ' + + 'link[type="application/atom+xml"], ' + + 'link[rel="alternate"][type="application/json"]', + ) + const feeds = Array.from(feedNodes).map((link) => ({ href: (link as HTMLLinkElement).href, title: (link as HTMLLinkElement).title, - })); + })) - return JSON.stringify({search, feeds}); + return JSON.stringify({ search, feeds }) } -const pageMetadataApi = new CrWebApi('pageMetadata'); -pageMetadataApi.addFunction('getMetadata', getMetadata); -gCrWeb.registerApi(pageMetadataApi); +const pageMetadataApi = new CrWebApi('pageMetadata') +pageMetadataApi.addFunction('getMetadata', getMetadata) +gCrWeb.registerApi(pageMetadataApi) diff --git a/ios/browser/web/reader_mode/resources/brave_reader_mode.ts b/ios/browser/web/reader_mode/resources/brave_reader_mode.ts index 9a204ae9a99..59dc220af11 100644 --- a/ios/browser/web/reader_mode/resources/brave_reader_mode.ts +++ b/ios/browser/web/reader_mode/resources/brave_reader_mode.ts @@ -3,226 +3,240 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {CrWebApi, gCrWeb} from - '//ios/web/public/js_messaging/resources/gcrweb.js'; +import { + CrWebApi, + gCrWeb, +} from '//ios/web/public/js_messaging/resources/gcrweb.js' // Readability.js and Readability-readerable.js are injected as separate // FeatureScripts before this one and expose their APIs as globals. declare class Readability { constructor( - document: Document, - options?: { - debug?: boolean; maxElemsToParse?: number; nbTopCandidates?: number; - charThreshold?: number; - classesToPreserve?: string[]; - keepClasses?: boolean; - serializer?: (node: Node) => T; - disableJSONLD?: boolean; - allowedVideoRegex?: RegExp; - }); - parse(): null|{ - title: string | null | undefined; - content: T | null | undefined; - textContent: string | null | undefined; - length: number | null | undefined; - excerpt: string | null | undefined; - byline: string | null | undefined; - dir: string | null | undefined; - siteName: string | null | undefined; - lang: string | null | undefined; - publishedTime: string | null | undefined; - }; + document: Document, + options?: { + debug?: boolean + maxElemsToParse?: number + nbTopCandidates?: number + charThreshold?: number + classesToPreserve?: string[] + keepClasses?: boolean + serializer?: (node: Node) => T + disableJSONLD?: boolean + allowedVideoRegex?: RegExp + }, + ) + parse(): null | { + title: string | null | undefined + content: T | null | undefined + textContent: string | null | undefined + length: number | null | undefined + excerpt: string | null | undefined + byline: string | null | undefined + dir: string | null | undefined + siteName: string | null | undefined + lang: string | null | undefined + publishedTime: string | null | undefined + } } declare function isProbablyReaderable( - document: Document, - options?: { - minContentLength?: number; - minScore?: number; - visibilityChecker?: (node: Node) => boolean; - }): boolean; + document: Document, + options?: { + minContentLength?: number + minScore?: number + visibilityChecker?: (node: Node) => boolean + }, +): boolean -type ReadabilityParseResult = ReturnType; +type ReadabilityParseResult = ReturnType interface ExtendedParseResult extends NonNullable { - cspMetaTags?: string[]; - documentLanguage?: string; + cspMetaTags?: string[] + documentLanguage?: string } -const kReaderModeURL = /^internal:\/\/local\/reader-mode/; +const kReaderModeURL = /^internal:\/\/local\/reader-mode/ const kBlockImagesSelector = - '.content p > img:only-child, ' + - '.content p > a:only-child > img:only-child, ' + - '.content .wp-caption img, ' + - '.content figure img'; + '.content p > img:only-child, ' + + '.content p > a:only-child > img:only-child, ' + + '.content .wp-caption img, ' + + '.content figure img' -let readabilityResult: ExtendedParseResult|null = null; +let readabilityResult: ExtendedParseResult | null = null interface ReaderModeStyle { - theme?: string; - fontSize?: number; - fontType?: string; + theme?: string + fontSize?: number + fontType?: string } -let currentStyle: ReaderModeStyle|null = null; +let currentStyle: ReaderModeStyle | null = null -function checkReadability(): string|null { +function checkReadability(): string | null { if (!isProbablyReaderable(document)) { - return null; + return null } // Short circuit if Readability already ran (back/forward cache hit). if (readabilityResult && readabilityResult['content']) { - return JSON.stringify(readabilityResult); + return JSON.stringify(readabilityResult) } // Serialize then re-parse to avoid cloneNode crashes (bug 1128774). - const docStr = new XMLSerializer().serializeToString(document); + const docStr = new XMLSerializer().serializeToString(document) // Skip documents with to avoid WKWebView crashes (bug 1489543). if (docStr.includes(' 0) { - readabilityResult.cspMetaTags = - Array.from(cspMetaTags) - .map((e) => e.getAttribute('content') ?? '') - .filter(Boolean); + readabilityResult.cspMetaTags = Array.from(cspMetaTags) + .map((e) => e.getAttribute('content') ?? '') + .filter(Boolean) } const documentLanguage = - document.documentElement.lang || - document.querySelector('meta[http-equiv="Content-Language"]') - ?.getAttribute('content') || - null; + document.documentElement.lang + || document + .querySelector('meta[http-equiv="Content-Language"]') + ?.getAttribute('content') + || null if (documentLanguage) { - readabilityResult.documentLanguage = documentLanguage; + readabilityResult.documentLanguage = documentLanguage } - return JSON.stringify(readabilityResult); + return JSON.stringify(readabilityResult) } function setStyle(style: ReaderModeStyle): void { if (currentStyle?.theme) { - document.body.classList.remove(currentStyle.theme); + document.body.classList.remove(currentStyle.theme) } if (style?.theme) { - document.body.classList.add(style.theme); + document.body.classList.add(style.theme) } if (currentStyle?.fontSize !== undefined) { - document.body.classList.remove('font-size' + currentStyle.fontSize); + document.body.classList.remove('font-size' + currentStyle.fontSize) } if (style?.fontSize !== undefined) { - document.body.classList.add('font-size' + style.fontSize); + document.body.classList.add('font-size' + style.fontSize) } if (currentStyle?.fontType) { - document.body.classList.remove(currentStyle.fontType); + document.body.classList.remove(currentStyle.fontType) } if (style?.fontType) { - document.body.classList.add(style.fontType); + document.body.classList.add(style.fontType) } - currentStyle = style; + currentStyle = style } function updateImageMargins(): void { - const contentElement = document.getElementById('reader-content'); + const contentElement = document.getElementById('reader-content') if (!contentElement) { - return; + return } - const windowWidth = window.innerWidth; - const contentWidth = contentElement.offsetWidth; - const maxWidthStyle = windowWidth + 'px !important'; + const windowWidth = window.innerWidth + const contentWidth = contentElement.offsetWidth + const maxWidthStyle = windowWidth + 'px !important' - type ImgWithOriginalWidth = - HTMLImageElement&{_originalWidth?: number}; + type ImgWithOriginalWidth = HTMLImageElement & { _originalWidth?: number } const setImageMargins = (img: ImgWithOriginalWidth): void => { if (!img._originalWidth) { - img._originalWidth = img.offsetWidth; + img._originalWidth = img.offsetWidth } - let imgWidth = img._originalWidth; + let imgWidth = img._originalWidth if (imgWidth < contentWidth && imgWidth > windowWidth * 0.55) { - imgWidth = windowWidth; + imgWidth = windowWidth } - const sideMargin = - Math.max( - (contentWidth - windowWidth) / 2, - (contentWidth - imgWidth) / 2); + const sideMargin = Math.max( + (contentWidth - windowWidth) / 2, + (contentWidth - imgWidth) / 2, + ) img.style.cssText = - 'max-width: ' + maxWidthStyle + ';' + - 'width: ' + imgWidth + 'px !important;' + - 'margin-left: ' + sideMargin + 'px !important;' + - 'margin-right: ' + sideMargin + 'px !important;'; - }; + 'max-width: ' + + maxWidthStyle + + ';' + + 'width: ' + + imgWidth + + 'px !important;' + + 'margin-left: ' + + sideMargin + + 'px !important;' + + 'margin-right: ' + + sideMargin + + 'px !important;' + } const imgs = - document.querySelectorAll(kBlockImagesSelector); + document.querySelectorAll(kBlockImagesSelector) for (let i = imgs.length - 1; i >= 0; i--) { - const img = imgs[i]; + const img = imgs[i] if (!img) { - continue; + continue } if (img.width > 0) { - setImageMargins(img); + setImageMargins(img) } else { - img.onload = () => setImageMargins(img); + img.onload = () => setImageMargins(img) } } } function showContent(): void { - const messageElement = document.getElementById('reader-message'); + const messageElement = document.getElementById('reader-message') if (messageElement) { - messageElement.style.display = 'none'; + messageElement.style.display = 'none' } - const headerElement = document.getElementById('reader-header'); + const headerElement = document.getElementById('reader-header') if (headerElement) { - headerElement.style.display = 'block'; + headerElement.style.display = 'block' } - const contentElement = document.getElementById('reader-content'); + const contentElement = document.getElementById('reader-content') if (contentElement) { - contentElement.style.display = 'block'; + contentElement.style.display = 'block' } } function configureReader(): void { - const styleAttr = document.body.getAttribute('data-readerStyle'); + const styleAttr = document.body.getAttribute('data-readerStyle') if (styleAttr) { - setStyle(JSON.parse(styleAttr) as ReaderModeStyle); + setStyle(JSON.parse(styleAttr) as ReaderModeStyle) } - showContent(); - updateImageMargins(); + showContent() + updateImageMargins() } window.addEventListener('load', () => { if (document.location.href.match(kReaderModeURL)) { - configureReader(); + configureReader() } -}); +}) -const readerModeApi = new CrWebApi('readerMode'); -readerModeApi.addFunction('checkReadability', checkReadability); -readerModeApi.addFunction('setStyle', setStyle); -gCrWeb.registerApi(readerModeApi); +const readerModeApi = new CrWebApi('readerMode') +readerModeApi.addFunction('checkReadability', checkReadability) +readerModeApi.addFunction('setStyle', setStyle) +gCrWeb.registerApi(readerModeApi) diff --git a/ios/browser/youtube/resources/yt_video_quality.ts b/ios/browser/youtube/resources/yt_video_quality.ts index f1334a5c468..96c0c5d79fc 100644 --- a/ios/browser/youtube/resources/yt_video_quality.ts +++ b/ios/browser/youtube/resources/yt_video_quality.ts @@ -3,11 +3,12 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {CrWebApi, gCrWeb} from - '//ios/web/public/js_messaging/resources/gcrweb.js'; -import {resetQuality} from - '//brave/ios/browser/youtube/resources/yt_video_quality_utils.js'; +import { + CrWebApi, + gCrWeb, +} from '//ios/web/public/js_messaging/resources/gcrweb.js' +import { resetQuality } from '//brave/ios/browser/youtube/resources/yt_video_quality_utils.js' -const youtubeQualityApi = new CrWebApi('youtubeQuality'); -youtubeQualityApi.addFunction('resetQuality', resetQuality); -gCrWeb.registerApi(youtubeQualityApi); +const youtubeQualityApi = new CrWebApi('youtubeQuality') +youtubeQualityApi.addFunction('resetQuality', resetQuality) +gCrWeb.registerApi(youtubeQualityApi) diff --git a/ios/browser/youtube/resources/yt_video_quality_event_listeners.ts b/ios/browser/youtube/resources/yt_video_quality_event_listeners.ts index 0acb2f21df9..189b78229ab 100644 --- a/ios/browser/youtube/resources/yt_video_quality_event_listeners.ts +++ b/ios/browser/youtube/resources/yt_video_quality_event_listeners.ts @@ -3,28 +3,27 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {functionAsListener} from '//ios/web/public/js_messaging/resources/utils.js'; -import {requestVideoQualityPreference} from - '//brave/ios/browser/youtube/resources/yt_video_quality_utils.js'; +import { functionAsListener } from '//ios/web/public/js_messaging/resources/utils.js' +import { requestVideoQualityPreference } from '//brave/ios/browser/youtube/resources/yt_video_quality_utils.js' const allowedOrigins = [ 'https://youtube.com', 'https://www.youtube.com', 'https://m.youtube.com', -]; +] if (allowedOrigins.includes(window.location.origin)) { - const listener = functionAsListener(requestVideoQualityPreference); + const listener = functionAsListener(requestVideoQualityPreference) // Apply quality when the video element finishes loading data (covers the // initial load as well as mid-session source changes). - document.addEventListener('loadeddata', listener, {capture: true}); + document.addEventListener('loadeddata', listener, { capture: true }) // YouTube uses History API (pushState) for in-app navigation. The page // dispatches 'yt-navigate-finish' on document when each navigation // settles. - document.addEventListener('yt-navigate-finish', listener); + document.addEventListener('yt-navigate-finish', listener) // Attempt to apply the highest quality immediately - requestVideoQualityPreference(); + requestVideoQualityPreference() } diff --git a/ios/browser/youtube/resources/yt_video_quality_utils.ts b/ios/browser/youtube/resources/yt_video_quality_utils.ts index 2e354bb813c..12326189c1f 100644 --- a/ios/browser/youtube/resources/yt_video_quality_utils.ts +++ b/ios/browser/youtube/resources/yt_video_quality_utils.ts @@ -3,39 +3,44 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {sendWebKitMessageWithReply} from - '//ios/web/public/js_messaging/resources/utils.js'; +import { sendWebKitMessageWithReply } from '//ios/web/public/js_messaging/resources/utils.js' function findPlayer(): any { - return document.getElementById('movie_player') || - document.querySelector('.html5-video-player'); + return ( + document.getElementById('movie_player') + || document.querySelector('.html5-video-player') + ) } export function applyHighestQuality(): void { - const player = findPlayer(); - if (!player || typeof player.getAvailableQualityLevels === 'undefined' || - !player.setPlaybackQualityRange) { - return; + const player = findPlayer() + if ( + !player + || typeof player.getAvailableQualityLevels === 'undefined' + || !player.setPlaybackQualityRange + ) { + return } - const qualities: string[] = player.getAvailableQualityLevels(); + const qualities: string[] = player.getAvailableQualityLevels() if (qualities && qualities.length > 0) { - player.setPlaybackQualityRange(qualities[0], qualities[0]); + player.setPlaybackQualityRange(qualities[0], qualities[0]) } } export function resetQuality(): void { - const player = findPlayer(); + const player = findPlayer() if (!player || !player.setPlaybackQualityRange) { - return; + return } - player.setPlaybackQualityRange('auto', 'auto'); + player.setPlaybackQualityRange('auto', 'auto') } export function requestVideoQualityPreference() { - sendWebKitMessageWithReply('YouTubeQualityMessageHandler', {}) - .then((shouldApplyHighestQuality: boolean) => { + sendWebKitMessageWithReply('YouTubeQualityMessageHandler', {}).then( + (shouldApplyHighestQuality: boolean) => { if (shouldApplyHighestQuality) { - applyHighestQuality(); + applyHighestQuality() } - }); + }, + ) } diff --git a/ios/web/js_messaging/resources/message_handler_token_test_api.ts b/ios/web/js_messaging/resources/message_handler_token_test_api.ts index b4f4e2c704d..03a1978269d 100644 --- a/ios/web/js_messaging/resources/message_handler_token_test_api.ts +++ b/ios/web/js_messaging/resources/message_handler_token_test_api.ts @@ -3,18 +3,21 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {CrWebApi, gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js'; -import {sendTokenizedWebKitMessage} from "//brave/ios/web/js_messaging/resources/utils.js"; -import {sendWebKitMessage} from "//ios/web/public/js_messaging/resources/utils.js"; +import { + CrWebApi, + gCrWeb, +} from '//ios/web/public/js_messaging/resources/gcrweb.js' +import { sendTokenizedWebKitMessage } from '//brave/ios/web/js_messaging/resources/utils.js' +import { sendWebKitMessage } from '//ios/web/public/js_messaging/resources/utils.js' function send() { - sendTokenizedWebKitMessage('ScriptHandlerName', {'key': 'value'}); + sendTokenizedWebKitMessage('ScriptHandlerName', { 'key': 'value' }) } function sendInvalid() { - sendWebKitMessage('ScriptHandlerName', {'key': 'value'}); + sendWebKitMessage('ScriptHandlerName', { 'key': 'value' }) } -const testApi = new CrWebApi('message_handler_token_tests'); -testApi.addFunction('sendTokenizedWebKitMessage', send); -testApi.addFunction('sendWebKitMessage', sendInvalid); -gCrWeb.registerApi(testApi); +const testApi = new CrWebApi('message_handler_token_tests') +testApi.addFunction('sendTokenizedWebKitMessage', send) +testApi.addFunction('sendWebKitMessage', sendInvalid) +gCrWeb.registerApi(testApi) diff --git a/ios/web/js_messaging/resources/randomized_message_handler_test_api.ts b/ios/web/js_messaging/resources/randomized_message_handler_test_api.ts index d204e5d5a33..7bd7a1e1f4b 100644 --- a/ios/web/js_messaging/resources/randomized_message_handler_test_api.ts +++ b/ios/web/js_messaging/resources/randomized_message_handler_test_api.ts @@ -3,14 +3,17 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import {messageHandlerName} from "//brave/ios/web/js_messaging/resources/utils.js"; -import {CrWebApi, gCrWeb} from '//ios/web/public/js_messaging/resources/gcrweb.js'; -import {sendWebKitMessage} from "//ios/web/public/js_messaging/resources/utils.js"; +import { messageHandlerName } from '//brave/ios/web/js_messaging/resources/utils.js' +import { + CrWebApi, + gCrWeb, +} from '//ios/web/public/js_messaging/resources/gcrweb.js' +import { sendWebKitMessage } from '//ios/web/public/js_messaging/resources/utils.js' function send() { - sendWebKitMessage(messageHandlerName, {}); + sendWebKitMessage(messageHandlerName, {}) } -const testApi = new CrWebApi('randomized_message_handler_tests'); -testApi.addFunction('sendWebKitMessage', send); -gCrWeb.registerApi(testApi); +const testApi = new CrWebApi('randomized_message_handler_tests') +testApi.addFunction('sendWebKitMessage', send) +gCrWeb.registerApi(testApi) diff --git a/ios/web/js_messaging/resources/safe_builtins.ts b/ios/web/js_messaging/resources/safe_builtins.ts index 4f30dfc28d7..59edadd24e1 100644 --- a/ios/web/js_messaging/resources/safe_builtins.ts +++ b/ios/web/js_messaging/resources/safe_builtins.ts @@ -5,105 +5,126 @@ declare global { interface Window { - webkit: any; + webkit: any } } class SafeBuiltins { - readonly $Object: typeof Object = this.secureCopy(Object); - readonly $Function: typeof Function = this.secureCopy(Function); - readonly $Array: typeof Array = this.secureCopy(Array); - readonly $ = function(value: any): any { return value; } + readonly $Object: typeof Object = this.secureCopy(Object) + readonly $Function: typeof Function = this.secureCopy(Function) + readonly $Array: typeof Array = this.secureCopy(Array) + readonly $ = function (value: any): any { + return value + } // Sends a message to a script message handler in the browser - readonly sendWebKitMessage: (handlerName: string, message: object|string) => void; + readonly sendWebKitMessage: ( + handlerName: string, + message: object | string, + ) => void // Sends a message to a script message handler in the browser and returns a // Promise that resolves when the browser replies - readonly sendWebKitMessageWithReply: (handlerName: string, message: object|string) => Promise; + readonly sendWebKitMessageWithReply: ( + handlerName: string, + message: object | string, + ) => Promise // Send a message expecting synchronously by using window.prompt and returns // the reply from the browser. - readonly sendWebKitMessageSynchronously: (handlerName: string, message: object|string) => any|null; + readonly sendWebKitMessageSynchronously: ( + handlerName: string, + message: object | string, + ) => any | null constructor() { // Setup private refs to capture in safe builtin functions - const webkitMessageHandlers = window.webkit.messageHandlers; - const windowPrompt = window.prompt.bind(window); - const jsonStringify = JSON.stringify.bind(JSON); - const jsonParse = JSON.parse.bind(JSON); + const webkitMessageHandlers = window.webkit.messageHandlers + const windowPrompt = window.prompt.bind(window) + const jsonStringify = JSON.stringify.bind(JSON) + const jsonParse = JSON.parse.bind(JSON) this.sendWebKitMessage = (handlerName, message) => { - webkitMessageHandlers[handlerName].postMessage(message); + webkitMessageHandlers[handlerName].postMessage(message) } this.sendWebKitMessageWithReply = (handlerName, message) => { - return webkitMessageHandlers[handlerName].postMessage(message); + return webkitMessageHandlers[handlerName].postMessage(message) } this.sendWebKitMessageSynchronously = (handlerName, message) => { - const response = windowPrompt(jsonStringify({ - handler: handlerName, - message: message - })); + const response = windowPrompt( + jsonStringify({ + handler: handlerName, + message: message, + }), + ) if (!response) { - return null; + return null } try { return jsonParse(response) } catch { - return null; + return null } } // Freeze all the safe builtins and any function we export - for (const value of [this.$Object, this.$Function, this.$Array, this.$, - this.sendWebKitMessage, this.sendWebKitMessageWithReply]) { - this.deepFreeze(value); + for (const value of [ + this.$Object, + this.$Function, + this.$Array, + this.$, + this.sendWebKitMessage, + this.sendWebKitMessageWithReply, + ]) { + this.deepFreeze(value) } } // Freeze an object and its prototype private deepFreeze(value: any) { if (!value) { - return; + return } - this.$Object.freeze(value); - const prototype = (value as any).prototype; + this.$Object.freeze(value) + const prototype = (value as any).prototype if (prototype) { - this.$Object.freeze(prototype); + this.$Object.freeze(prototype) } } // Copies an object's signature to an object with no prototype to prevent // prototype polution attacks private secureCopy(value: any): any { - let prototypeProperties = Object.create(null, value.prototype ? - Object.getOwnPropertyDescriptors(value.prototype) : {}); - delete prototypeProperties['prototype']; + let prototypeProperties = Object.create( + null, + value.prototype ? Object.getOwnPropertyDescriptors(value.prototype) : {}, + ) + delete prototypeProperties['prototype'] let properties = Object.assign( Object.create(null), Object.getOwnPropertyDescriptors(value), - value.prototype ? Object.getOwnPropertyDescriptors(value.prototype) : - {} - ); + value.prototype ? Object.getOwnPropertyDescriptors(value.prototype) : {}, + ) // Do not copy the prototype. - delete properties['prototype']; + delete properties['prototype'] return new Proxy(Object.create(null, properties), { get(target, property, _receiver) { if (property == 'prototype') { - return prototypeProperties; + return prototypeProperties } - return target[property]; - } - }); + return target[property] + }, + }) } } -type SafeBuiltinsType = Window&(typeof globalThis)&{readonly __gSafeBuiltins: SafeBuiltins}; +type SafeBuiltinsType = Window + & typeof globalThis & { readonly __gSafeBuiltins: SafeBuiltins } // Initializes window's `__gSafeBuiltins` property. if (!(window as SafeBuiltinsType).__gSafeBuiltins) { @@ -111,14 +132,15 @@ if (!(window as SafeBuiltinsType).__gSafeBuiltins) { value: Object.freeze(new SafeBuiltins()), writable: false, configurable: false, - enumerable: false - }); + enumerable: false, + }) } -export const gSafeBuiltins: SafeBuiltins = (window as SafeBuiltinsType).__gSafeBuiltins; +export const gSafeBuiltins: SafeBuiltins = (window as SafeBuiltinsType) + .__gSafeBuiltins // Export some shortcuts to items in SafeBuiltins -export const $Object = gSafeBuiltins.$Object; -export const $Function = gSafeBuiltins.$Function; -export const $Array = gSafeBuiltins.$Array; -export const $ = gSafeBuiltins.$; +export const $Object = gSafeBuiltins.$Object +export const $Function = gSafeBuiltins.$Function +export const $Array = gSafeBuiltins.$Array +export const $ = gSafeBuiltins.$ diff --git a/ios/web/js_messaging/resources/utils.ts b/ios/web/js_messaging/resources/utils.ts index 10e15e2768f..2136043bbcb 100644 --- a/ios/web/js_messaging/resources/utils.ts +++ b/ios/web/js_messaging/resources/utils.ts @@ -3,33 +3,36 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at https://mozilla.org/MPL/2.0/. -import { gSafeBuiltins } - from "//brave/ios/web/js_messaging/resources/safe_builtins.js"; +import { gSafeBuiltins } from '//brave/ios/web/js_messaging/resources/safe_builtins.js' // The message handler name to use with sendWebKitMessage when your JavaScript // feature supports randomized message handler names. -export const messageHandlerName: string = 'gCrWebPlaceholderMessageHandlerName'; +export const messageHandlerName: string = 'gCrWebPlaceholderMessageHandlerName' // A token to be used for validating communication with the browser -const messageHandlerToken: string = 'gCrWebPlaceholderMessageHandlerToken'; +const messageHandlerToken: string = 'gCrWebPlaceholderMessageHandlerToken' // Posts `message` to the webkit message handler specified by `handlerName` and // embeds a token for the browser to validate export function sendTokenizedWebKitMessage( - handlerName: string, message: object|string) { + handlerName: string, + message: object | string, +) { gSafeBuiltins.sendWebKitMessage(handlerName, { token: messageHandlerToken, - message: message - }); + message: message, + }) } // Posts `message` to the webkit message handler specified by `handlerName` and // embeds a token for the browser to validate and waits for a reply export function sendTokenizedWebKitMessageWithReply( - handlerName: string, message: object|string): Promise { + handlerName: string, + message: object | string, +): Promise { return gSafeBuiltins.sendWebKitMessageWithReply(handlerName, { token: messageHandlerToken, - message: message + message: message, }) } @@ -37,9 +40,11 @@ export function sendTokenizedWebKitMessageWithReply( // validation and waits for the reply synchronously. If the message isnt valid // JSON or the response cannot be parsed as JSON then this returns null export function sendTokenizedWebKitMessageSynchronously( - handlerName: string, message: object|string): any|null { + handlerName: string, + message: object | string, +): any | null { return gSafeBuiltins.sendWebKitMessageSynchronously(handlerName, { token: messageHandlerToken, - message: message + message: message, }) }