(data, info, isXml)
| 131 | * @param {boolean} isXml |
| 132 | */ |
| 133 | export async function injectScripts(data, info, isXml) { |
| 134 | const { errors, [MORE]: more } = data; |
| 135 | const BODY = 'body'; |
| 136 | const CACHE = 'cache'; |
| 137 | if (errors) { |
| 138 | logging.warn(errors); |
| 139 | } |
| 140 | info.gmi = { |
| 141 | isIncognito: chrome.extension.inIncognitoContext, |
| 142 | }; |
| 143 | bridgeInfo = createNullObj(); |
| 144 | bridgeInfo[PAGE] = info; |
| 145 | bridgeInfo[CONTENT] = info; |
| 146 | assign(bridge[CACHE], data[CACHE]); |
| 147 | if (isXml || data[FORCE_CONTENT]) { |
| 148 | pageInjectable = false; |
| 149 | } else if (data[PAGE] && pageInjectable == null) { |
| 150 | injectPageSandbox(data); |
| 151 | } |
| 152 | const toContent = data[SCRIPTS] |
| 153 | .filter(scr => triageScript(scr) === CONTENT) |
| 154 | .map(scr => [scr.id, scr.key.data]); |
| 155 | const moreData = (more || toContent.length) |
| 156 | && sendFeedback(toContent, more); |
| 157 | const getReadyState = more && describeProperty(Document[PROTO], 'readyState').get; |
| 158 | const wasInjectableFF = IS_FIREFOX && !nonce && pageInjectable; |
| 159 | const pageBodyScripts = pageLists?.[BODY]; |
| 160 | if (wasInjectableFF) { |
| 161 | getAttribute = Element[PROTO].getAttribute; |
| 162 | querySelector = document.querySelector; |
| 163 | } |
| 164 | tardyQueue = createNullObj(); |
| 165 | // Using a callback to avoid a microtask tick when the root element exists or appears. |
| 166 | await onElement('*', injectAll, 'start'); |
| 167 | if (pageBodyScripts || contLists?.[BODY]) { |
| 168 | await onElement(BODY, !wasInjectableFF || !pageBodyScripts ? injectAll : arg => { |
| 169 | if (didPageLoseInjectability(toContent, pageBodyScripts)) { |
| 170 | pageLists = null; |
| 171 | contLists ??= createNullObj(); |
| 172 | const arr = contLists[BODY]; |
| 173 | if (arr) { |
| 174 | for (const scr of pageBodyScripts) safePush(arr, scr); |
| 175 | } else { |
| 176 | contLists[BODY] = pageBodyScripts; |
| 177 | } |
| 178 | sendFeedback(toContent); |
| 179 | } |
| 180 | injectAll(arg); |
| 181 | }, BODY); |
| 182 | } |
| 183 | if (more && (data = await moreData)) { |
| 184 | assign(bridge[CACHE], data[CACHE]); |
| 185 | if (document::getReadyState() === 'loading') { |
| 186 | await new SafePromise(resolve => { |
| 187 | /* Since most sites listen to DOMContentLoaded on `document`, we let them run first |
| 188 | * by listening on `window` which follows `document` when the event bubbles up. */ |
| 189 | on('DOMContentLoaded', resolve, { once: true }); |
| 190 | }); |
no test coverage detected