@browserless.io/browserless 2.0.0-beta-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (875) hide show
  1. package/CHANGELOG.md +674 -0
  2. package/LICENSE +6 -0
  3. package/README.md +132 -0
  4. package/assets/logo.png +0 -0
  5. package/bin/browserless.js +227 -0
  6. package/browser.json +7 -0
  7. package/build/browserless.d.ts +33 -0
  8. package/build/browserless.js +146 -0
  9. package/build/browsers/cdp-chromium.d.ts +41 -0
  10. package/build/browsers/cdp-chromium.js +287 -0
  11. package/build/browsers/index.d.ts +26 -0
  12. package/build/browsers/index.js +183 -0
  13. package/build/browsers/playwright-chromium.d.ts +34 -0
  14. package/build/browsers/playwright-chromium.js +106 -0
  15. package/build/browsers/playwright-firefox.d.ts +34 -0
  16. package/build/browsers/playwright-firefox.js +101 -0
  17. package/build/browsers/playwright-webkit.d.ts +34 -0
  18. package/build/browsers/playwright-webkit.js +101 -0
  19. package/build/config.d.ts +138 -0
  20. package/build/config.js +349 -0
  21. package/build/constants.d.ts +4 -0
  22. package/build/constants.js +4 -0
  23. package/build/data/classes.json +1 -0
  24. package/build/data/selectors.json +1 -0
  25. package/build/exports.d.ts +20 -0
  26. package/build/exports.js +22 -0
  27. package/build/file-system.d.ts +24 -0
  28. package/build/file-system.js +46 -0
  29. package/build/hooks.d.ts +5 -0
  30. package/build/hooks.js +20 -0
  31. package/build/http.d.ts +175 -0
  32. package/build/http.js +104 -0
  33. package/build/index.d.ts +1 -0
  34. package/build/index.js +39 -0
  35. package/build/limiter.d.ts +24 -0
  36. package/build/limiter.js +147 -0
  37. package/build/limiter.spec.d.ts +1 -0
  38. package/build/limiter.spec.js +241 -0
  39. package/build/metrics.d.ts +24 -0
  40. package/build/metrics.js +86 -0
  41. package/build/metrics.spec.d.ts +1 -0
  42. package/build/metrics.spec.js +35 -0
  43. package/build/mime-types.d.ts +1 -0
  44. package/build/mime-types.js +328 -0
  45. package/build/monitoring.d.ts +13 -0
  46. package/build/monitoring.js +38 -0
  47. package/build/routes/chromium/http/content-post.body.json +514 -0
  48. package/build/routes/chromium/http/content-post.d.ts +34 -0
  49. package/build/routes/chromium/http/content-post.js +109 -0
  50. package/build/routes/chromium/http/content-post.query.json +183 -0
  51. package/build/routes/chromium/http/content-post.response.json +5 -0
  52. package/build/routes/chromium/http/download-post.body.json +32 -0
  53. package/build/routes/chromium/http/download-post.d.ts +16 -0
  54. package/build/routes/chromium/http/download-post.js +92 -0
  55. package/build/routes/chromium/http/download-post.query.json +120 -0
  56. package/build/routes/chromium/http/download-post.response.json +4 -0
  57. package/build/routes/chromium/http/function-post.body.json +32 -0
  58. package/build/routes/chromium/http/function-post.d.ts +18 -0
  59. package/build/routes/chromium/http/function-post.js +53 -0
  60. package/build/routes/chromium/http/function-post.query.json +120 -0
  61. package/build/routes/chromium/http/function-post.response.json +4 -0
  62. package/build/routes/chromium/http/pdf-post.body.json +654 -0
  63. package/build/routes/chromium/http/pdf-post.d.ts +35 -0
  64. package/build/routes/chromium/http/pdf-post.js +107 -0
  65. package/build/routes/chromium/http/pdf-post.query.json +120 -0
  66. package/build/routes/chromium/http/pdf-post.response.json +5 -0
  67. package/build/routes/chromium/http/performance.body.json +26 -0
  68. package/build/routes/chromium/http/performance.d.ts +17 -0
  69. package/build/routes/chromium/http/performance.js +30 -0
  70. package/build/routes/chromium/http/performance.query.json +120 -0
  71. package/build/routes/chromium/http/performance.response.json +7 -0
  72. package/build/routes/chromium/http/scrape-post.body.json +561 -0
  73. package/build/routes/chromium/http/scrape-post.d.ts +106 -0
  74. package/build/routes/chromium/http/scrape-post.js +205 -0
  75. package/build/routes/chromium/http/scrape-post.query.json +183 -0
  76. package/build/routes/chromium/http/scrape-post.response.json +325 -0
  77. package/build/routes/chromium/http/screenshot-post.body.json +604 -0
  78. package/build/routes/chromium/http/screenshot-post.d.ts +37 -0
  79. package/build/routes/chromium/http/screenshot-post.js +124 -0
  80. package/build/routes/chromium/http/screenshot-post.query.json +120 -0
  81. package/build/routes/chromium/http/screenshot-post.response.json +5 -0
  82. package/build/routes/chromium/tests/content.spec.d.ts +1 -0
  83. package/build/routes/chromium/tests/content.spec.js +285 -0
  84. package/build/routes/chromium/tests/download.spec.d.ts +1 -0
  85. package/build/routes/chromium/tests/download.spec.js +67 -0
  86. package/build/routes/chromium/tests/function.spec.d.ts +1 -0
  87. package/build/routes/chromium/tests/function.spec.js +245 -0
  88. package/build/routes/chromium/tests/pdf.spec.d.ts +1 -0
  89. package/build/routes/chromium/tests/pdf.spec.js +333 -0
  90. package/build/routes/chromium/tests/performance.spec.d.ts +1 -0
  91. package/build/routes/chromium/tests/performance.spec.js +124 -0
  92. package/build/routes/chromium/tests/scrape.spec.d.ts +1 -0
  93. package/build/routes/chromium/tests/scrape.spec.js +354 -0
  94. package/build/routes/chromium/tests/screenshot.spec.d.ts +1 -0
  95. package/build/routes/chromium/tests/screenshot.spec.js +339 -0
  96. package/build/routes/chromium/tests/websocket.spec.d.ts +1 -0
  97. package/build/routes/chromium/tests/websocket.spec.js +309 -0
  98. package/build/routes/chromium/utils/function/client.d.ts +26 -0
  99. package/build/routes/chromium/utils/function/client.js +66 -0
  100. package/build/routes/chromium/utils/function/handler.d.ts +18 -0
  101. package/build/routes/chromium/utils/function/handler.js +95 -0
  102. package/build/routes/chromium/utils/performance/child.d.ts +1 -0
  103. package/build/routes/chromium/utils/performance/child.js +29 -0
  104. package/build/routes/chromium/utils/performance/main.d.ts +3 -0
  105. package/build/routes/chromium/utils/performance/main.js +65 -0
  106. package/build/routes/chromium/utils/performance/types.d.ts +21 -0
  107. package/build/routes/chromium/utils/performance/types.js +1 -0
  108. package/build/routes/chromium/ws/browser.d.ts +6 -0
  109. package/build/routes/chromium/ws/browser.js +11 -0
  110. package/build/routes/chromium/ws/browser.query.json +120 -0
  111. package/build/routes/chromium/ws/cdp-chromium.d.ts +6 -0
  112. package/build/routes/chromium/ws/cdp-chromium.js +11 -0
  113. package/build/routes/chromium/ws/cdp-chromium.query.json +120 -0
  114. package/build/routes/chromium/ws/page.d.ts +6 -0
  115. package/build/routes/chromium/ws/page.js +11 -0
  116. package/build/routes/chromium/ws/page.query.json +120 -0
  117. package/build/routes/chromium/ws/playwright-chromium.d.ts +6 -0
  118. package/build/routes/chromium/ws/playwright-chromium.js +19 -0
  119. package/build/routes/chromium/ws/playwright-chromium.query.json +100 -0
  120. package/build/routes/firefox/tests/websocket.spec.d.ts +1 -0
  121. package/build/routes/firefox/tests/websocket.spec.js +104 -0
  122. package/build/routes/firefox/ws/playwright-firefox.d.ts +6 -0
  123. package/build/routes/firefox/ws/playwright-firefox.js +19 -0
  124. package/build/routes/firefox/ws/playwright-firefox.query.json +100 -0
  125. package/build/routes/management/http/config-get.d.ts +25 -0
  126. package/build/routes/management/http/config-get.js +43 -0
  127. package/build/routes/management/http/config-get.response.json +107 -0
  128. package/build/routes/management/http/metrics-get.d.ts +4 -0
  129. package/build/routes/management/http/metrics-get.js +24 -0
  130. package/build/routes/management/http/metrics-get.response.json +94 -0
  131. package/build/routes/management/http/metrics-total-get.d.ts +4 -0
  132. package/build/routes/management/http/metrics-total-get.js +60 -0
  133. package/build/routes/management/http/metrics-total-get.response.json +72 -0
  134. package/build/routes/management/http/sessions-get.d.ts +4 -0
  135. package/build/routes/management/http/sessions-get.js +21 -0
  136. package/build/routes/management/http/sessions-get.response.json +221 -0
  137. package/build/routes/management/http/static-get.d.ts +3 -0
  138. package/build/routes/management/http/static-get.js +67 -0
  139. package/build/routes/management/tests/management.spec.d.ts +1 -0
  140. package/build/routes/management/tests/management.spec.js +41 -0
  141. package/build/routes/webkit/tests/websocket.spec.d.ts +1 -0
  142. package/build/routes/webkit/tests/websocket.spec.js +104 -0
  143. package/build/routes/webkit/ws/playwright-webkit.d.ts +6 -0
  144. package/build/routes/webkit/ws/playwright-webkit.js +19 -0
  145. package/build/routes/webkit/ws/playwright-webkit.query.json +100 -0
  146. package/build/server.d.ts +38 -0
  147. package/build/server.js +365 -0
  148. package/build/shim.d.ts +9 -0
  149. package/build/shim.js +54 -0
  150. package/build/shim.spec.d.ts +1 -0
  151. package/build/shim.spec.js +114 -0
  152. package/build/types.d.ts +360 -0
  153. package/build/types.js +6 -0
  154. package/build/utils.d.ts +111 -0
  155. package/build/utils.js +570 -0
  156. package/build/webhooks.d.ts +11 -0
  157. package/build/webhooks.js +43 -0
  158. package/docker/base/.dockerignore +16 -0
  159. package/docker/base/Dockerfile +70 -0
  160. package/docker/chrome/.dockerignore +16 -0
  161. package/docker/chrome/Dockerfile +40 -0
  162. package/docker/firefox/.dockerignore +16 -0
  163. package/docker/firefox/Dockerfile +39 -0
  164. package/docker/multi/.dockerignore +16 -0
  165. package/docker/multi/Dockerfile +37 -0
  166. package/docker/sdk/.dockerignore +16 -0
  167. package/docker/sdk/Dockerfile +34 -0
  168. package/docker/webkit/.dockerignore +16 -0
  169. package/docker/webkit/Dockerfile +40 -0
  170. package/extensions/screencast/background.js +143 -0
  171. package/extensions/screencast/content_script.js +18 -0
  172. package/extensions/screencast/manifest.json +19 -0
  173. package/extensions/ublock/1p-filters.html +69 -0
  174. package/extensions/ublock/3p-filters.html +119 -0
  175. package/extensions/ublock/LICENSE.txt +674 -0
  176. package/extensions/ublock/_locales/ar/messages.json +1290 -0
  177. package/extensions/ublock/_locales/az/messages.json +1290 -0
  178. package/extensions/ublock/_locales/be/messages.json +1290 -0
  179. package/extensions/ublock/_locales/bg/messages.json +1290 -0
  180. package/extensions/ublock/_locales/bn/messages.json +1290 -0
  181. package/extensions/ublock/_locales/br_FR/messages.json +1290 -0
  182. package/extensions/ublock/_locales/bs/messages.json +1290 -0
  183. package/extensions/ublock/_locales/ca/messages.json +1290 -0
  184. package/extensions/ublock/_locales/cs/messages.json +1290 -0
  185. package/extensions/ublock/_locales/cv/messages.json +1290 -0
  186. package/extensions/ublock/_locales/da/messages.json +1290 -0
  187. package/extensions/ublock/_locales/de/messages.json +1290 -0
  188. package/extensions/ublock/_locales/el/messages.json +1290 -0
  189. package/extensions/ublock/_locales/en/messages.json +1292 -0
  190. package/extensions/ublock/_locales/en_GB/messages.json +1290 -0
  191. package/extensions/ublock/_locales/eo/messages.json +1290 -0
  192. package/extensions/ublock/_locales/es/messages.json +1290 -0
  193. package/extensions/ublock/_locales/et/messages.json +1290 -0
  194. package/extensions/ublock/_locales/eu/messages.json +1290 -0
  195. package/extensions/ublock/_locales/fa/messages.json +1290 -0
  196. package/extensions/ublock/_locales/fi/messages.json +1290 -0
  197. package/extensions/ublock/_locales/fil/messages.json +1290 -0
  198. package/extensions/ublock/_locales/fr/messages.json +1290 -0
  199. package/extensions/ublock/_locales/fy/messages.json +1290 -0
  200. package/extensions/ublock/_locales/gl/messages.json +1290 -0
  201. package/extensions/ublock/_locales/gu/messages.json +1290 -0
  202. package/extensions/ublock/_locales/he/messages.json +1290 -0
  203. package/extensions/ublock/_locales/hi/messages.json +1290 -0
  204. package/extensions/ublock/_locales/hr/messages.json +1290 -0
  205. package/extensions/ublock/_locales/hu/messages.json +1290 -0
  206. package/extensions/ublock/_locales/hy/messages.json +1290 -0
  207. package/extensions/ublock/_locales/id/messages.json +1290 -0
  208. package/extensions/ublock/_locales/it/messages.json +1290 -0
  209. package/extensions/ublock/_locales/ja/messages.json +1290 -0
  210. package/extensions/ublock/_locales/ka/messages.json +1290 -0
  211. package/extensions/ublock/_locales/kk/messages.json +1290 -0
  212. package/extensions/ublock/_locales/kn/messages.json +1290 -0
  213. package/extensions/ublock/_locales/ko/messages.json +1290 -0
  214. package/extensions/ublock/_locales/ku/messages.json +1290 -0
  215. package/extensions/ublock/_locales/lt/messages.json +1290 -0
  216. package/extensions/ublock/_locales/lv/messages.json +1290 -0
  217. package/extensions/ublock/_locales/mk/messages.json +1290 -0
  218. package/extensions/ublock/_locales/ml/messages.json +1290 -0
  219. package/extensions/ublock/_locales/mr/messages.json +1290 -0
  220. package/extensions/ublock/_locales/ms/messages.json +1290 -0
  221. package/extensions/ublock/_locales/nb/messages.json +1290 -0
  222. package/extensions/ublock/_locales/nl/messages.json +1290 -0
  223. package/extensions/ublock/_locales/no/messages.json +1290 -0
  224. package/extensions/ublock/_locales/oc/messages.json +1290 -0
  225. package/extensions/ublock/_locales/pa/messages.json +1290 -0
  226. package/extensions/ublock/_locales/pl/messages.json +1290 -0
  227. package/extensions/ublock/_locales/pt_BR/messages.json +1290 -0
  228. package/extensions/ublock/_locales/pt_PT/messages.json +1290 -0
  229. package/extensions/ublock/_locales/ro/messages.json +1290 -0
  230. package/extensions/ublock/_locales/ru/messages.json +1290 -0
  231. package/extensions/ublock/_locales/si/messages.json +1290 -0
  232. package/extensions/ublock/_locales/sk/messages.json +1290 -0
  233. package/extensions/ublock/_locales/sl/messages.json +1290 -0
  234. package/extensions/ublock/_locales/so/messages.json +1290 -0
  235. package/extensions/ublock/_locales/sq/messages.json +1290 -0
  236. package/extensions/ublock/_locales/sr/messages.json +1290 -0
  237. package/extensions/ublock/_locales/sv/messages.json +1290 -0
  238. package/extensions/ublock/_locales/sw/messages.json +1290 -0
  239. package/extensions/ublock/_locales/ta/messages.json +1290 -0
  240. package/extensions/ublock/_locales/te/messages.json +1290 -0
  241. package/extensions/ublock/_locales/th/messages.json +1290 -0
  242. package/extensions/ublock/_locales/tr/messages.json +1290 -0
  243. package/extensions/ublock/_locales/uk/messages.json +1290 -0
  244. package/extensions/ublock/_locales/ur/messages.json +1290 -0
  245. package/extensions/ublock/_locales/vi/messages.json +1290 -0
  246. package/extensions/ublock/_locales/zh_CN/messages.json +1290 -0
  247. package/extensions/ublock/_locales/zh_TW/messages.json +1290 -0
  248. package/extensions/ublock/about.html +63 -0
  249. package/extensions/ublock/advanced-settings.html +42 -0
  250. package/extensions/ublock/asset-viewer.html +50 -0
  251. package/extensions/ublock/assets/assets.json +903 -0
  252. package/extensions/ublock/assets/resources/scriptlets.js +4255 -0
  253. package/extensions/ublock/assets/thirdparties/easylist/easylist.txt +65576 -0
  254. package/extensions/ublock/assets/thirdparties/easylist/easyprivacy.txt +33219 -0
  255. package/extensions/ublock/assets/thirdparties/pgl.yoyo.org/as/README.md +29 -0
  256. package/extensions/ublock/assets/thirdparties/pgl.yoyo.org/as/serverlist +3732 -0
  257. package/extensions/ublock/assets/thirdparties/publicsuffix.org/list/effective_tld_names.dat +15431 -0
  258. package/extensions/ublock/assets/thirdparties/urlhaus-filter/LICENSE.md +42 -0
  259. package/extensions/ublock/assets/thirdparties/urlhaus-filter/urlhaus-filter-online.txt +1970 -0
  260. package/extensions/ublock/assets/ublock/badlists.txt +77 -0
  261. package/extensions/ublock/assets/ublock/badware.min.txt +3033 -0
  262. package/extensions/ublock/assets/ublock/filters.min.txt +23419 -0
  263. package/extensions/ublock/assets/ublock/privacy.min.txt +575 -0
  264. package/extensions/ublock/assets/ublock/quick-fixes.min.txt +99 -0
  265. package/extensions/ublock/assets/ublock/unbreak.min.txt +2448 -0
  266. package/extensions/ublock/background.html +12 -0
  267. package/extensions/ublock/cloud-ui.html +23 -0
  268. package/extensions/ublock/code-viewer.html +53 -0
  269. package/extensions/ublock/css/1p-filters.css +26 -0
  270. package/extensions/ublock/css/3p-filters.css +250 -0
  271. package/extensions/ublock/css/about.css +3 -0
  272. package/extensions/ublock/css/advanced-settings.css +26 -0
  273. package/extensions/ublock/css/asset-viewer.css +79 -0
  274. package/extensions/ublock/css/click2load.css +53 -0
  275. package/extensions/ublock/css/cloud-ui.css +104 -0
  276. package/extensions/ublock/css/code-viewer.css +67 -0
  277. package/extensions/ublock/css/codemirror.css +326 -0
  278. package/extensions/ublock/css/common.css +347 -0
  279. package/extensions/ublock/css/dashboard-common.css +55 -0
  280. package/extensions/ublock/css/dashboard.css +115 -0
  281. package/extensions/ublock/css/devtools.css +22 -0
  282. package/extensions/ublock/css/document-blocked.css +146 -0
  283. package/extensions/ublock/css/dyna-rules.css +79 -0
  284. package/extensions/ublock/css/epicker-ui.css +270 -0
  285. package/extensions/ublock/css/fa-icons.css +149 -0
  286. package/extensions/ublock/css/fonts/Inter/Inter-Regular.woff2 +0 -0
  287. package/extensions/ublock/css/fonts/Inter/Inter-SemiBold.woff2 +0 -0
  288. package/extensions/ublock/css/fonts/Inter/LICENSE.txt +93 -0
  289. package/extensions/ublock/css/fonts/Metropolis/Metropolis-Regular.woff2 +0 -0
  290. package/extensions/ublock/css/fonts/Metropolis/Metropolis-SemiBold.woff2 +0 -0
  291. package/extensions/ublock/css/fonts/Metropolis/README.md +25 -0
  292. package/extensions/ublock/css/fonts/Metropolis/UNLICENSE +24 -0
  293. package/extensions/ublock/css/logger-ui-inspector.css +116 -0
  294. package/extensions/ublock/css/logger-ui.css +978 -0
  295. package/extensions/ublock/css/popup-fenix.css +778 -0
  296. package/extensions/ublock/css/settings.css +74 -0
  297. package/extensions/ublock/css/support.css +110 -0
  298. package/extensions/ublock/css/themes/default.css +526 -0
  299. package/extensions/ublock/css/whitelist.css +22 -0
  300. package/extensions/ublock/dashboard.html +47 -0
  301. package/extensions/ublock/devtools.html +58 -0
  302. package/extensions/ublock/document-blocked.html +64 -0
  303. package/extensions/ublock/dyna-rules.html +67 -0
  304. package/extensions/ublock/img/cloud.png +0 -0
  305. package/extensions/ublock/img/flags-of-the-world/README +9 -0
  306. package/extensions/ublock/img/flags-of-the-world/ad.png +0 -0
  307. package/extensions/ublock/img/flags-of-the-world/ae.png +0 -0
  308. package/extensions/ublock/img/flags-of-the-world/af.png +0 -0
  309. package/extensions/ublock/img/flags-of-the-world/ag.png +0 -0
  310. package/extensions/ublock/img/flags-of-the-world/ai.png +0 -0
  311. package/extensions/ublock/img/flags-of-the-world/al.png +0 -0
  312. package/extensions/ublock/img/flags-of-the-world/am.png +0 -0
  313. package/extensions/ublock/img/flags-of-the-world/ao.png +0 -0
  314. package/extensions/ublock/img/flags-of-the-world/aq.png +0 -0
  315. package/extensions/ublock/img/flags-of-the-world/ar.png +0 -0
  316. package/extensions/ublock/img/flags-of-the-world/as.png +0 -0
  317. package/extensions/ublock/img/flags-of-the-world/at.png +0 -0
  318. package/extensions/ublock/img/flags-of-the-world/au.png +0 -0
  319. package/extensions/ublock/img/flags-of-the-world/aw.png +0 -0
  320. package/extensions/ublock/img/flags-of-the-world/ax.png +0 -0
  321. package/extensions/ublock/img/flags-of-the-world/az.png +0 -0
  322. package/extensions/ublock/img/flags-of-the-world/ba.png +0 -0
  323. package/extensions/ublock/img/flags-of-the-world/bb.png +0 -0
  324. package/extensions/ublock/img/flags-of-the-world/bd.png +0 -0
  325. package/extensions/ublock/img/flags-of-the-world/be.png +0 -0
  326. package/extensions/ublock/img/flags-of-the-world/bf.png +0 -0
  327. package/extensions/ublock/img/flags-of-the-world/bg.png +0 -0
  328. package/extensions/ublock/img/flags-of-the-world/bh.png +0 -0
  329. package/extensions/ublock/img/flags-of-the-world/bi.png +0 -0
  330. package/extensions/ublock/img/flags-of-the-world/bj.png +0 -0
  331. package/extensions/ublock/img/flags-of-the-world/bl.png +0 -0
  332. package/extensions/ublock/img/flags-of-the-world/bm.png +0 -0
  333. package/extensions/ublock/img/flags-of-the-world/bn.png +0 -0
  334. package/extensions/ublock/img/flags-of-the-world/bo.png +0 -0
  335. package/extensions/ublock/img/flags-of-the-world/bq.png +0 -0
  336. package/extensions/ublock/img/flags-of-the-world/br.png +0 -0
  337. package/extensions/ublock/img/flags-of-the-world/bs.png +0 -0
  338. package/extensions/ublock/img/flags-of-the-world/bt.png +0 -0
  339. package/extensions/ublock/img/flags-of-the-world/bv.png +0 -0
  340. package/extensions/ublock/img/flags-of-the-world/bw.png +0 -0
  341. package/extensions/ublock/img/flags-of-the-world/by.png +0 -0
  342. package/extensions/ublock/img/flags-of-the-world/bz.png +0 -0
  343. package/extensions/ublock/img/flags-of-the-world/ca.png +0 -0
  344. package/extensions/ublock/img/flags-of-the-world/cc.png +0 -0
  345. package/extensions/ublock/img/flags-of-the-world/cd.png +0 -0
  346. package/extensions/ublock/img/flags-of-the-world/cf.png +0 -0
  347. package/extensions/ublock/img/flags-of-the-world/cg.png +0 -0
  348. package/extensions/ublock/img/flags-of-the-world/ch.png +0 -0
  349. package/extensions/ublock/img/flags-of-the-world/ci.png +0 -0
  350. package/extensions/ublock/img/flags-of-the-world/ck.png +0 -0
  351. package/extensions/ublock/img/flags-of-the-world/cl.png +0 -0
  352. package/extensions/ublock/img/flags-of-the-world/cm.png +0 -0
  353. package/extensions/ublock/img/flags-of-the-world/cn.png +0 -0
  354. package/extensions/ublock/img/flags-of-the-world/co.png +0 -0
  355. package/extensions/ublock/img/flags-of-the-world/cr.png +0 -0
  356. package/extensions/ublock/img/flags-of-the-world/cu.png +0 -0
  357. package/extensions/ublock/img/flags-of-the-world/cv.png +0 -0
  358. package/extensions/ublock/img/flags-of-the-world/cw.png +0 -0
  359. package/extensions/ublock/img/flags-of-the-world/cx.png +0 -0
  360. package/extensions/ublock/img/flags-of-the-world/cy.png +0 -0
  361. package/extensions/ublock/img/flags-of-the-world/cz.png +0 -0
  362. package/extensions/ublock/img/flags-of-the-world/de.png +0 -0
  363. package/extensions/ublock/img/flags-of-the-world/dj.png +0 -0
  364. package/extensions/ublock/img/flags-of-the-world/dk.png +0 -0
  365. package/extensions/ublock/img/flags-of-the-world/dm.png +0 -0
  366. package/extensions/ublock/img/flags-of-the-world/do.png +0 -0
  367. package/extensions/ublock/img/flags-of-the-world/dz.png +0 -0
  368. package/extensions/ublock/img/flags-of-the-world/ec.png +0 -0
  369. package/extensions/ublock/img/flags-of-the-world/ee.png +0 -0
  370. package/extensions/ublock/img/flags-of-the-world/eg.png +0 -0
  371. package/extensions/ublock/img/flags-of-the-world/eh.png +0 -0
  372. package/extensions/ublock/img/flags-of-the-world/er.png +0 -0
  373. package/extensions/ublock/img/flags-of-the-world/es.png +0 -0
  374. package/extensions/ublock/img/flags-of-the-world/et.png +0 -0
  375. package/extensions/ublock/img/flags-of-the-world/fi.png +0 -0
  376. package/extensions/ublock/img/flags-of-the-world/fj.png +0 -0
  377. package/extensions/ublock/img/flags-of-the-world/fk.png +0 -0
  378. package/extensions/ublock/img/flags-of-the-world/fm.png +0 -0
  379. package/extensions/ublock/img/flags-of-the-world/fo.png +0 -0
  380. package/extensions/ublock/img/flags-of-the-world/fr.png +0 -0
  381. package/extensions/ublock/img/flags-of-the-world/ga.png +0 -0
  382. package/extensions/ublock/img/flags-of-the-world/gb-eng.png +0 -0
  383. package/extensions/ublock/img/flags-of-the-world/gb-nir.png +0 -0
  384. package/extensions/ublock/img/flags-of-the-world/gb-sct.png +0 -0
  385. package/extensions/ublock/img/flags-of-the-world/gb-wls.png +0 -0
  386. package/extensions/ublock/img/flags-of-the-world/gb.png +0 -0
  387. package/extensions/ublock/img/flags-of-the-world/gd.png +0 -0
  388. package/extensions/ublock/img/flags-of-the-world/ge.png +0 -0
  389. package/extensions/ublock/img/flags-of-the-world/gf.png +0 -0
  390. package/extensions/ublock/img/flags-of-the-world/gg.png +0 -0
  391. package/extensions/ublock/img/flags-of-the-world/gh.png +0 -0
  392. package/extensions/ublock/img/flags-of-the-world/gi.png +0 -0
  393. package/extensions/ublock/img/flags-of-the-world/gl.png +0 -0
  394. package/extensions/ublock/img/flags-of-the-world/gm.png +0 -0
  395. package/extensions/ublock/img/flags-of-the-world/gn.png +0 -0
  396. package/extensions/ublock/img/flags-of-the-world/gp.png +0 -0
  397. package/extensions/ublock/img/flags-of-the-world/gq.png +0 -0
  398. package/extensions/ublock/img/flags-of-the-world/gr.png +0 -0
  399. package/extensions/ublock/img/flags-of-the-world/gs.png +0 -0
  400. package/extensions/ublock/img/flags-of-the-world/gt.png +0 -0
  401. package/extensions/ublock/img/flags-of-the-world/gu.png +0 -0
  402. package/extensions/ublock/img/flags-of-the-world/gw.png +0 -0
  403. package/extensions/ublock/img/flags-of-the-world/gy.png +0 -0
  404. package/extensions/ublock/img/flags-of-the-world/hk.png +0 -0
  405. package/extensions/ublock/img/flags-of-the-world/hm.png +0 -0
  406. package/extensions/ublock/img/flags-of-the-world/hn.png +0 -0
  407. package/extensions/ublock/img/flags-of-the-world/hr.png +0 -0
  408. package/extensions/ublock/img/flags-of-the-world/ht.png +0 -0
  409. package/extensions/ublock/img/flags-of-the-world/hu.png +0 -0
  410. package/extensions/ublock/img/flags-of-the-world/id.png +0 -0
  411. package/extensions/ublock/img/flags-of-the-world/ie.png +0 -0
  412. package/extensions/ublock/img/flags-of-the-world/il.png +0 -0
  413. package/extensions/ublock/img/flags-of-the-world/im.png +0 -0
  414. package/extensions/ublock/img/flags-of-the-world/in.png +0 -0
  415. package/extensions/ublock/img/flags-of-the-world/io.png +0 -0
  416. package/extensions/ublock/img/flags-of-the-world/iq.png +0 -0
  417. package/extensions/ublock/img/flags-of-the-world/ir.png +0 -0
  418. package/extensions/ublock/img/flags-of-the-world/is.png +0 -0
  419. package/extensions/ublock/img/flags-of-the-world/it.png +0 -0
  420. package/extensions/ublock/img/flags-of-the-world/je.png +0 -0
  421. package/extensions/ublock/img/flags-of-the-world/jm.png +0 -0
  422. package/extensions/ublock/img/flags-of-the-world/jo.png +0 -0
  423. package/extensions/ublock/img/flags-of-the-world/jp.png +0 -0
  424. package/extensions/ublock/img/flags-of-the-world/ke.png +0 -0
  425. package/extensions/ublock/img/flags-of-the-world/kg.png +0 -0
  426. package/extensions/ublock/img/flags-of-the-world/kh.png +0 -0
  427. package/extensions/ublock/img/flags-of-the-world/ki.png +0 -0
  428. package/extensions/ublock/img/flags-of-the-world/km.png +0 -0
  429. package/extensions/ublock/img/flags-of-the-world/kn.png +0 -0
  430. package/extensions/ublock/img/flags-of-the-world/kp.png +0 -0
  431. package/extensions/ublock/img/flags-of-the-world/kr.png +0 -0
  432. package/extensions/ublock/img/flags-of-the-world/kw.png +0 -0
  433. package/extensions/ublock/img/flags-of-the-world/ky.png +0 -0
  434. package/extensions/ublock/img/flags-of-the-world/kz.png +0 -0
  435. package/extensions/ublock/img/flags-of-the-world/la.png +0 -0
  436. package/extensions/ublock/img/flags-of-the-world/lb.png +0 -0
  437. package/extensions/ublock/img/flags-of-the-world/lc.png +0 -0
  438. package/extensions/ublock/img/flags-of-the-world/li.png +0 -0
  439. package/extensions/ublock/img/flags-of-the-world/lk.png +0 -0
  440. package/extensions/ublock/img/flags-of-the-world/lr.png +0 -0
  441. package/extensions/ublock/img/flags-of-the-world/ls.png +0 -0
  442. package/extensions/ublock/img/flags-of-the-world/lt.png +0 -0
  443. package/extensions/ublock/img/flags-of-the-world/lu.png +0 -0
  444. package/extensions/ublock/img/flags-of-the-world/lv.png +0 -0
  445. package/extensions/ublock/img/flags-of-the-world/ly.png +0 -0
  446. package/extensions/ublock/img/flags-of-the-world/ma.png +0 -0
  447. package/extensions/ublock/img/flags-of-the-world/mc.png +0 -0
  448. package/extensions/ublock/img/flags-of-the-world/md.png +0 -0
  449. package/extensions/ublock/img/flags-of-the-world/me.png +0 -0
  450. package/extensions/ublock/img/flags-of-the-world/mf.png +0 -0
  451. package/extensions/ublock/img/flags-of-the-world/mg.png +0 -0
  452. package/extensions/ublock/img/flags-of-the-world/mh.png +0 -0
  453. package/extensions/ublock/img/flags-of-the-world/mk.png +0 -0
  454. package/extensions/ublock/img/flags-of-the-world/ml.png +0 -0
  455. package/extensions/ublock/img/flags-of-the-world/mm.png +0 -0
  456. package/extensions/ublock/img/flags-of-the-world/mn.png +0 -0
  457. package/extensions/ublock/img/flags-of-the-world/mo.png +0 -0
  458. package/extensions/ublock/img/flags-of-the-world/mp.png +0 -0
  459. package/extensions/ublock/img/flags-of-the-world/mq.png +0 -0
  460. package/extensions/ublock/img/flags-of-the-world/mr.png +0 -0
  461. package/extensions/ublock/img/flags-of-the-world/ms.png +0 -0
  462. package/extensions/ublock/img/flags-of-the-world/mt.png +0 -0
  463. package/extensions/ublock/img/flags-of-the-world/mu.png +0 -0
  464. package/extensions/ublock/img/flags-of-the-world/mv.png +0 -0
  465. package/extensions/ublock/img/flags-of-the-world/mw.png +0 -0
  466. package/extensions/ublock/img/flags-of-the-world/mx.png +0 -0
  467. package/extensions/ublock/img/flags-of-the-world/my.png +0 -0
  468. package/extensions/ublock/img/flags-of-the-world/mz.png +0 -0
  469. package/extensions/ublock/img/flags-of-the-world/na.png +0 -0
  470. package/extensions/ublock/img/flags-of-the-world/nc.png +0 -0
  471. package/extensions/ublock/img/flags-of-the-world/ne.png +0 -0
  472. package/extensions/ublock/img/flags-of-the-world/nf.png +0 -0
  473. package/extensions/ublock/img/flags-of-the-world/ng.png +0 -0
  474. package/extensions/ublock/img/flags-of-the-world/ni.png +0 -0
  475. package/extensions/ublock/img/flags-of-the-world/nl.png +0 -0
  476. package/extensions/ublock/img/flags-of-the-world/no.png +0 -0
  477. package/extensions/ublock/img/flags-of-the-world/np.png +0 -0
  478. package/extensions/ublock/img/flags-of-the-world/nr.png +0 -0
  479. package/extensions/ublock/img/flags-of-the-world/nu.png +0 -0
  480. package/extensions/ublock/img/flags-of-the-world/nz.png +0 -0
  481. package/extensions/ublock/img/flags-of-the-world/om.png +0 -0
  482. package/extensions/ublock/img/flags-of-the-world/pa.png +0 -0
  483. package/extensions/ublock/img/flags-of-the-world/pe.png +0 -0
  484. package/extensions/ublock/img/flags-of-the-world/pf.png +0 -0
  485. package/extensions/ublock/img/flags-of-the-world/pg.png +0 -0
  486. package/extensions/ublock/img/flags-of-the-world/ph.png +0 -0
  487. package/extensions/ublock/img/flags-of-the-world/pk.png +0 -0
  488. package/extensions/ublock/img/flags-of-the-world/pl.png +0 -0
  489. package/extensions/ublock/img/flags-of-the-world/pm.png +0 -0
  490. package/extensions/ublock/img/flags-of-the-world/pn.png +0 -0
  491. package/extensions/ublock/img/flags-of-the-world/pr.png +0 -0
  492. package/extensions/ublock/img/flags-of-the-world/ps.png +0 -0
  493. package/extensions/ublock/img/flags-of-the-world/pt.png +0 -0
  494. package/extensions/ublock/img/flags-of-the-world/pw.png +0 -0
  495. package/extensions/ublock/img/flags-of-the-world/py.png +0 -0
  496. package/extensions/ublock/img/flags-of-the-world/qa.png +0 -0
  497. package/extensions/ublock/img/flags-of-the-world/re.png +0 -0
  498. package/extensions/ublock/img/flags-of-the-world/ro.png +0 -0
  499. package/extensions/ublock/img/flags-of-the-world/rs.png +0 -0
  500. package/extensions/ublock/img/flags-of-the-world/ru.png +0 -0
  501. package/extensions/ublock/img/flags-of-the-world/rw.png +0 -0
  502. package/extensions/ublock/img/flags-of-the-world/sa.png +0 -0
  503. package/extensions/ublock/img/flags-of-the-world/sb.png +0 -0
  504. package/extensions/ublock/img/flags-of-the-world/sc.png +0 -0
  505. package/extensions/ublock/img/flags-of-the-world/sd.png +0 -0
  506. package/extensions/ublock/img/flags-of-the-world/se.png +0 -0
  507. package/extensions/ublock/img/flags-of-the-world/sg.png +0 -0
  508. package/extensions/ublock/img/flags-of-the-world/sh.png +0 -0
  509. package/extensions/ublock/img/flags-of-the-world/si.png +0 -0
  510. package/extensions/ublock/img/flags-of-the-world/sj.png +0 -0
  511. package/extensions/ublock/img/flags-of-the-world/sk.png +0 -0
  512. package/extensions/ublock/img/flags-of-the-world/sl.png +0 -0
  513. package/extensions/ublock/img/flags-of-the-world/sm.png +0 -0
  514. package/extensions/ublock/img/flags-of-the-world/sn.png +0 -0
  515. package/extensions/ublock/img/flags-of-the-world/so.png +0 -0
  516. package/extensions/ublock/img/flags-of-the-world/sr.png +0 -0
  517. package/extensions/ublock/img/flags-of-the-world/ss.png +0 -0
  518. package/extensions/ublock/img/flags-of-the-world/st.png +0 -0
  519. package/extensions/ublock/img/flags-of-the-world/sv.png +0 -0
  520. package/extensions/ublock/img/flags-of-the-world/sx.png +0 -0
  521. package/extensions/ublock/img/flags-of-the-world/sy.png +0 -0
  522. package/extensions/ublock/img/flags-of-the-world/sz.png +0 -0
  523. package/extensions/ublock/img/flags-of-the-world/tc.png +0 -0
  524. package/extensions/ublock/img/flags-of-the-world/td.png +0 -0
  525. package/extensions/ublock/img/flags-of-the-world/tf.png +0 -0
  526. package/extensions/ublock/img/flags-of-the-world/tg.png +0 -0
  527. package/extensions/ublock/img/flags-of-the-world/th.png +0 -0
  528. package/extensions/ublock/img/flags-of-the-world/tj.png +0 -0
  529. package/extensions/ublock/img/flags-of-the-world/tk.png +0 -0
  530. package/extensions/ublock/img/flags-of-the-world/tl.png +0 -0
  531. package/extensions/ublock/img/flags-of-the-world/tm.png +0 -0
  532. package/extensions/ublock/img/flags-of-the-world/tn.png +0 -0
  533. package/extensions/ublock/img/flags-of-the-world/to.png +0 -0
  534. package/extensions/ublock/img/flags-of-the-world/tr.png +0 -0
  535. package/extensions/ublock/img/flags-of-the-world/tt.png +0 -0
  536. package/extensions/ublock/img/flags-of-the-world/tv.png +0 -0
  537. package/extensions/ublock/img/flags-of-the-world/tw.png +0 -0
  538. package/extensions/ublock/img/flags-of-the-world/tz.png +0 -0
  539. package/extensions/ublock/img/flags-of-the-world/ua.png +0 -0
  540. package/extensions/ublock/img/flags-of-the-world/ug.png +0 -0
  541. package/extensions/ublock/img/flags-of-the-world/um.png +0 -0
  542. package/extensions/ublock/img/flags-of-the-world/us.png +0 -0
  543. package/extensions/ublock/img/flags-of-the-world/uy.png +0 -0
  544. package/extensions/ublock/img/flags-of-the-world/uz.png +0 -0
  545. package/extensions/ublock/img/flags-of-the-world/va.png +0 -0
  546. package/extensions/ublock/img/flags-of-the-world/vc.png +0 -0
  547. package/extensions/ublock/img/flags-of-the-world/ve.png +0 -0
  548. package/extensions/ublock/img/flags-of-the-world/vg.png +0 -0
  549. package/extensions/ublock/img/flags-of-the-world/vi.png +0 -0
  550. package/extensions/ublock/img/flags-of-the-world/vn.png +0 -0
  551. package/extensions/ublock/img/flags-of-the-world/vu.png +0 -0
  552. package/extensions/ublock/img/flags-of-the-world/wf.png +0 -0
  553. package/extensions/ublock/img/flags-of-the-world/ws.png +0 -0
  554. package/extensions/ublock/img/flags-of-the-world/xk.png +0 -0
  555. package/extensions/ublock/img/flags-of-the-world/ye.png +0 -0
  556. package/extensions/ublock/img/flags-of-the-world/yt.png +0 -0
  557. package/extensions/ublock/img/flags-of-the-world/za.png +0 -0
  558. package/extensions/ublock/img/flags-of-the-world/zm.png +0 -0
  559. package/extensions/ublock/img/flags-of-the-world/zw.png +0 -0
  560. package/extensions/ublock/img/fontawesome/LICENSE.txt +25 -0
  561. package/extensions/ublock/img/fontawesome/fontawesome-defs.svg +79 -0
  562. package/extensions/ublock/img/help16.png +0 -0
  563. package/extensions/ublock/img/icon_128.png +0 -0
  564. package/extensions/ublock/img/icon_16-loading.png +0 -0
  565. package/extensions/ublock/img/icon_16-off.png +0 -0
  566. package/extensions/ublock/img/icon_16.png +0 -0
  567. package/extensions/ublock/img/icon_32-loading.png +0 -0
  568. package/extensions/ublock/img/icon_32-off.png +0 -0
  569. package/extensions/ublock/img/icon_32.png +0 -0
  570. package/extensions/ublock/img/icon_64-loading.png +0 -0
  571. package/extensions/ublock/img/icon_64-off.png +0 -0
  572. package/extensions/ublock/img/icon_64.png +0 -0
  573. package/extensions/ublock/img/material-design.svg +16 -0
  574. package/extensions/ublock/img/photon.svg +16 -0
  575. package/extensions/ublock/img/ublock-defs.svg +27 -0
  576. package/extensions/ublock/img/ublock.svg +44 -0
  577. package/extensions/ublock/is-webrtc-supported.html +9 -0
  578. package/extensions/ublock/js/1p-filters.js +336 -0
  579. package/extensions/ublock/js/3p-filters.js +867 -0
  580. package/extensions/ublock/js/about.js +34 -0
  581. package/extensions/ublock/js/advanced-settings.js +194 -0
  582. package/extensions/ublock/js/asset-viewer.js +112 -0
  583. package/extensions/ublock/js/assets.js +1448 -0
  584. package/extensions/ublock/js/background.js +404 -0
  585. package/extensions/ublock/js/base64-custom.js +246 -0
  586. package/extensions/ublock/js/benchmarks.js +421 -0
  587. package/extensions/ublock/js/biditrie.js +947 -0
  588. package/extensions/ublock/js/cachestorage.js +510 -0
  589. package/extensions/ublock/js/click2load.js +60 -0
  590. package/extensions/ublock/js/cloud-ui.js +238 -0
  591. package/extensions/ublock/js/code-viewer.js +311 -0
  592. package/extensions/ublock/js/codemirror/search-thread.js +199 -0
  593. package/extensions/ublock/js/codemirror/search.js +504 -0
  594. package/extensions/ublock/js/codemirror/ubo-dynamic-filtering.js +239 -0
  595. package/extensions/ublock/js/codemirror/ubo-static-filtering.js +1126 -0
  596. package/extensions/ublock/js/commands.js +181 -0
  597. package/extensions/ublock/js/console.js +59 -0
  598. package/extensions/ublock/js/contentscript-extra.js +662 -0
  599. package/extensions/ublock/js/contentscript.js +1366 -0
  600. package/extensions/ublock/js/contextmenu.js +270 -0
  601. package/extensions/ublock/js/cosmetic-filtering.js +983 -0
  602. package/extensions/ublock/js/dashboard-common.js +215 -0
  603. package/extensions/ublock/js/dashboard.js +166 -0
  604. package/extensions/ublock/js/devtools.js +184 -0
  605. package/extensions/ublock/js/diff-updater.js +288 -0
  606. package/extensions/ublock/js/document-blocked.js +230 -0
  607. package/extensions/ublock/js/dom.js +213 -0
  608. package/extensions/ublock/js/dyna-rules.js +678 -0
  609. package/extensions/ublock/js/dynamic-net-filtering.js +488 -0
  610. package/extensions/ublock/js/epicker-ui.js +924 -0
  611. package/extensions/ublock/js/fa-icons.js +129 -0
  612. package/extensions/ublock/js/filtering-context.js +461 -0
  613. package/extensions/ublock/js/filtering-engines.js +50 -0
  614. package/extensions/ublock/js/hnswitches.js +289 -0
  615. package/extensions/ublock/js/hntrie.js +780 -0
  616. package/extensions/ublock/js/html-filtering.js +465 -0
  617. package/extensions/ublock/js/httpheader-filtering.js +213 -0
  618. package/extensions/ublock/js/i18n.js +346 -0
  619. package/extensions/ublock/js/is-webrtc-supported.js +52 -0
  620. package/extensions/ublock/js/logger-ui-inspector.js +652 -0
  621. package/extensions/ublock/js/logger-ui.js +3028 -0
  622. package/extensions/ublock/js/logger.js +84 -0
  623. package/extensions/ublock/js/lz4.js +190 -0
  624. package/extensions/ublock/js/messaging.js +2095 -0
  625. package/extensions/ublock/js/pagestore.js +1140 -0
  626. package/extensions/ublock/js/popup-fenix.js +1529 -0
  627. package/extensions/ublock/js/redirect-engine.js +494 -0
  628. package/extensions/ublock/js/redirect-resources.js +193 -0
  629. package/extensions/ublock/js/reverselookup-worker.js +287 -0
  630. package/extensions/ublock/js/reverselookup.js +223 -0
  631. package/extensions/ublock/js/scriptlet-filtering.js +556 -0
  632. package/extensions/ublock/js/scriptlets/cosmetic-logger.js +376 -0
  633. package/extensions/ublock/js/scriptlets/cosmetic-off.js +48 -0
  634. package/extensions/ublock/js/scriptlets/cosmetic-on.js +48 -0
  635. package/extensions/ublock/js/scriptlets/cosmetic-report.js +142 -0
  636. package/extensions/ublock/js/scriptlets/dom-inspector.js +906 -0
  637. package/extensions/ublock/js/scriptlets/dom-survey-elements.js +72 -0
  638. package/extensions/ublock/js/scriptlets/dom-survey-scripts.js +126 -0
  639. package/extensions/ublock/js/scriptlets/epicker.js +1365 -0
  640. package/extensions/ublock/js/scriptlets/load-3p-css.js +67 -0
  641. package/extensions/ublock/js/scriptlets/load-large-media-all.js +62 -0
  642. package/extensions/ublock/js/scriptlets/load-large-media-interactive.js +299 -0
  643. package/extensions/ublock/js/scriptlets/noscript-spoof.js +89 -0
  644. package/extensions/ublock/js/scriptlets/should-inject-contentscript.js +40 -0
  645. package/extensions/ublock/js/scriptlets/subscriber.js +113 -0
  646. package/extensions/ublock/js/scriptlets/updater.js +101 -0
  647. package/extensions/ublock/js/settings.js +317 -0
  648. package/extensions/ublock/js/start.js +509 -0
  649. package/extensions/ublock/js/static-dnr-filtering.js +497 -0
  650. package/extensions/ublock/js/static-ext-filtering-db.js +171 -0
  651. package/extensions/ublock/js/static-ext-filtering.js +184 -0
  652. package/extensions/ublock/js/static-filtering-io.js +144 -0
  653. package/extensions/ublock/js/static-filtering-parser.js +4459 -0
  654. package/extensions/ublock/js/static-net-filtering.js +5631 -0
  655. package/extensions/ublock/js/storage.js +1683 -0
  656. package/extensions/ublock/js/support.js +335 -0
  657. package/extensions/ublock/js/tab.js +1178 -0
  658. package/extensions/ublock/js/tasks.js +42 -0
  659. package/extensions/ublock/js/text-encode.js +275 -0
  660. package/extensions/ublock/js/text-utils.js +107 -0
  661. package/extensions/ublock/js/theme.js +151 -0
  662. package/extensions/ublock/js/traffic.js +1260 -0
  663. package/extensions/ublock/js/ublock.js +696 -0
  664. package/extensions/ublock/js/uri-utils.js +175 -0
  665. package/extensions/ublock/js/url-net-filtering.js +336 -0
  666. package/extensions/ublock/js/utils.js +208 -0
  667. package/extensions/ublock/js/vapi-background-ext.js +254 -0
  668. package/extensions/ublock/js/vapi-background.js +1802 -0
  669. package/extensions/ublock/js/vapi-client-extra.js +312 -0
  670. package/extensions/ublock/js/vapi-client.js +280 -0
  671. package/extensions/ublock/js/vapi-common.js +308 -0
  672. package/extensions/ublock/js/vapi.js +89 -0
  673. package/extensions/ublock/js/wasm/README.md +24 -0
  674. package/extensions/ublock/js/wasm/biditrie.wasm +0 -0
  675. package/extensions/ublock/js/wasm/biditrie.wat +728 -0
  676. package/extensions/ublock/js/wasm/hntrie.wasm +0 -0
  677. package/extensions/ublock/js/wasm/hntrie.wat +724 -0
  678. package/extensions/ublock/js/webext.js +164 -0
  679. package/extensions/ublock/js/whitelist.js +258 -0
  680. package/extensions/ublock/lib/codemirror/LICENSE +21 -0
  681. package/extensions/ublock/lib/codemirror/README.md +47 -0
  682. package/extensions/ublock/lib/codemirror/addon/comment/comment.js +211 -0
  683. package/extensions/ublock/lib/codemirror/addon/display/panel.js +133 -0
  684. package/extensions/ublock/lib/codemirror/addon/edit/closebrackets.js +201 -0
  685. package/extensions/ublock/lib/codemirror/addon/edit/matchbrackets.js +160 -0
  686. package/extensions/ublock/lib/codemirror/addon/fold/foldcode.js +157 -0
  687. package/extensions/ublock/lib/codemirror/addon/fold/foldgutter.css +20 -0
  688. package/extensions/ublock/lib/codemirror/addon/fold/foldgutter.js +163 -0
  689. package/extensions/ublock/lib/codemirror/addon/hint/show-hint.css +36 -0
  690. package/extensions/ublock/lib/codemirror/addon/hint/show-hint.js +509 -0
  691. package/extensions/ublock/lib/codemirror/addon/merge/merge.css +119 -0
  692. package/extensions/ublock/lib/codemirror/addon/merge/merge.js +1006 -0
  693. package/extensions/ublock/lib/codemirror/addon/scroll/annotatescrollbar.js +128 -0
  694. package/extensions/ublock/lib/codemirror/addon/search/matchesonscrollbar.css +8 -0
  695. package/extensions/ublock/lib/codemirror/addon/search/searchcursor.js +296 -0
  696. package/extensions/ublock/lib/codemirror/addon/selection/active-line.js +72 -0
  697. package/extensions/ublock/lib/codemirror/lib/codemirror.css +350 -0
  698. package/extensions/ublock/lib/codemirror/lib/codemirror.js +9800 -0
  699. package/extensions/ublock/lib/codemirror/mode/css/css.js +864 -0
  700. package/extensions/ublock/lib/codemirror/mode/htmlmixed/htmlmixed.js +153 -0
  701. package/extensions/ublock/lib/codemirror/mode/javascript/javascript.js +942 -0
  702. package/extensions/ublock/lib/codemirror/mode/xml/xml.js +413 -0
  703. package/extensions/ublock/lib/codemirror/theme/night.css +27 -0
  704. package/extensions/ublock/lib/csstree/LICENSE +19 -0
  705. package/extensions/ublock/lib/csstree/css-tree.js +17 -0
  706. package/extensions/ublock/lib/diff/README.md +34 -0
  707. package/extensions/ublock/lib/diff/swatinem_diff.js +272 -0
  708. package/extensions/ublock/lib/hsluv/LICENSE +20 -0
  709. package/extensions/ublock/lib/hsluv/README +3 -0
  710. package/extensions/ublock/lib/hsluv/hsluv-0.1.0.min.js +8 -0
  711. package/extensions/ublock/lib/js-beautify/LICENSE +9 -0
  712. package/extensions/ublock/lib/js-beautify/README +5 -0
  713. package/extensions/ublock/lib/js-beautify/beautifier.min.js +2 -0
  714. package/extensions/ublock/lib/lz4/README.md +52 -0
  715. package/extensions/ublock/lib/lz4/lz4-block-codec-any.js +151 -0
  716. package/extensions/ublock/lib/lz4/lz4-block-codec-js.js +297 -0
  717. package/extensions/ublock/lib/lz4/lz4-block-codec-wasm.js +195 -0
  718. package/extensions/ublock/lib/lz4/lz4-block-codec.wasm +0 -0
  719. package/extensions/ublock/lib/lz4/lz4-block-codec.wat +745 -0
  720. package/extensions/ublock/lib/publicsuffixlist/publicsuffixlist.js +641 -0
  721. package/extensions/ublock/lib/publicsuffixlist/wasm/README.md +29 -0
  722. package/extensions/ublock/lib/publicsuffixlist/wasm/publicsuffixlist.wasm +0 -0
  723. package/extensions/ublock/lib/publicsuffixlist/wasm/publicsuffixlist.wat +322 -0
  724. package/extensions/ublock/lib/punycode.js +493 -0
  725. package/extensions/ublock/lib/regexanalyzer/CHANGES.md +15 -0
  726. package/extensions/ublock/lib/regexanalyzer/README.md +14 -0
  727. package/extensions/ublock/lib/regexanalyzer/regex.js +2276 -0
  728. package/extensions/ublock/logger-ui.html +232 -0
  729. package/extensions/ublock/managed_storage.json +73 -0
  730. package/extensions/ublock/manifest.json +115 -0
  731. package/extensions/ublock/no-dashboard.html +27 -0
  732. package/extensions/ublock/popup-fenix.html +114 -0
  733. package/extensions/ublock/settings.html +98 -0
  734. package/extensions/ublock/support.html +131 -0
  735. package/extensions/ublock/web_accessible_resources/1x1.gif +0 -0
  736. package/extensions/ublock/web_accessible_resources/2x2.png +0 -0
  737. package/extensions/ublock/web_accessible_resources/32x32.png +0 -0
  738. package/extensions/ublock/web_accessible_resources/3x2.png +0 -0
  739. package/extensions/ublock/web_accessible_resources/README.txt +11 -0
  740. package/extensions/ublock/web_accessible_resources/addthis_widget.js +39 -0
  741. package/extensions/ublock/web_accessible_resources/amazon_ads.js +70 -0
  742. package/extensions/ublock/web_accessible_resources/amazon_apstag.js +62 -0
  743. package/extensions/ublock/web_accessible_resources/ampproject_v0.js +34 -0
  744. package/extensions/ublock/web_accessible_resources/chartbeat.js +30 -0
  745. package/extensions/ublock/web_accessible_resources/click2load.html +28 -0
  746. package/extensions/ublock/web_accessible_resources/doubleclick_instream_ad_status.js +1 -0
  747. package/extensions/ublock/web_accessible_resources/empty +0 -0
  748. package/extensions/ublock/web_accessible_resources/epicker-ui.html +76 -0
  749. package/extensions/ublock/web_accessible_resources/fingerprint2.js +55 -0
  750. package/extensions/ublock/web_accessible_resources/fingerprint3.js +45 -0
  751. package/extensions/ublock/web_accessible_resources/google-analytics_analytics.js +110 -0
  752. package/extensions/ublock/web_accessible_resources/google-analytics_cx_api.js +36 -0
  753. package/extensions/ublock/web_accessible_resources/google-analytics_ga.js +130 -0
  754. package/extensions/ublock/web_accessible_resources/google-analytics_inpage_linkid.js +28 -0
  755. package/extensions/ublock/web_accessible_resources/google-ima.js +855 -0
  756. package/extensions/ublock/web_accessible_resources/googlesyndication_adsbygoogle.js +56 -0
  757. package/extensions/ublock/web_accessible_resources/googletagmanager_gtm.js +43 -0
  758. package/extensions/ublock/web_accessible_resources/googletagservices_gpt.js +153 -0
  759. package/extensions/ublock/web_accessible_resources/hd-main.js +46 -0
  760. package/extensions/ublock/web_accessible_resources/ligatus_angular-tag.js +29 -0
  761. package/extensions/ublock/web_accessible_resources/monkeybroker.js +43 -0
  762. package/extensions/ublock/web_accessible_resources/mxpnl_mixpanel.js +51 -0
  763. package/extensions/ublock/web_accessible_resources/nobab.js +87 -0
  764. package/extensions/ublock/web_accessible_resources/nobab2.js +42 -0
  765. package/extensions/ublock/web_accessible_resources/noeval-silent.js +28 -0
  766. package/extensions/ublock/web_accessible_resources/noeval.js +30 -0
  767. package/extensions/ublock/web_accessible_resources/nofab.js +67 -0
  768. package/extensions/ublock/web_accessible_resources/noop-0.1s.mp3 +0 -0
  769. package/extensions/ublock/web_accessible_resources/noop-0.5s.mp3 +0 -0
  770. package/extensions/ublock/web_accessible_resources/noop-1s.mp4 +0 -0
  771. package/extensions/ublock/web_accessible_resources/noop-vmap1.0.xml +1 -0
  772. package/extensions/ublock/web_accessible_resources/noop.css +1 -0
  773. package/extensions/ublock/web_accessible_resources/noop.html +5 -0
  774. package/extensions/ublock/web_accessible_resources/noop.js +3 -0
  775. package/extensions/ublock/web_accessible_resources/noop.json +1 -0
  776. package/extensions/ublock/web_accessible_resources/noop.txt +1 -0
  777. package/extensions/ublock/web_accessible_resources/outbrain-widget.js +72 -0
  778. package/extensions/ublock/web_accessible_resources/popads-dummy.js +30 -0
  779. package/extensions/ublock/web_accessible_resources/popads.js +40 -0
  780. package/extensions/ublock/web_accessible_resources/prebid-ads.js +26 -0
  781. package/extensions/ublock/web_accessible_resources/scorecardresearch_beacon.js +31 -0
  782. package/extensions/ublock/whitelist.html +63 -0
  783. package/external/.gitkeep +0 -0
  784. package/fonts/Calibri Bold Italic.ttf +0 -0
  785. package/fonts/Calibri Bold.TTF +0 -0
  786. package/fonts/Calibri Italic.ttf +0 -0
  787. package/fonts/Calibri Light Italic.ttf +0 -0
  788. package/fonts/Calibri Light.ttf +0 -0
  789. package/fonts/Calibri Regular.ttf +0 -0
  790. package/fonts/Emoji.ttf +0 -0
  791. package/fonts/SegoeUI-Bold.ttf +0 -0
  792. package/fonts/SegoeUI-Light.ttf +0 -0
  793. package/fonts/SegoeUI-Regular.ttf +0 -0
  794. package/fonts/SegoeUI-Semibold.ttf +0 -0
  795. package/fonts/SegoeUI-Semilight.ttf +0 -0
  796. package/fonts/Tahoma Bold.ttf +0 -0
  797. package/fonts/Tahoma.ttf +0 -0
  798. package/fonts/fonts.conf +21 -0
  799. package/package.json +177 -0
  800. package/scripts/build-function.js +18 -0
  801. package/scripts/build-open-api.js +274 -0
  802. package/scripts/build-schemas.js +86 -0
  803. package/scripts/build-selectors.js +36 -0
  804. package/scripts/clean.js +7 -0
  805. package/scripts/install-adblock.js +45 -0
  806. package/scripts/install-cdp-json.js +37 -0
  807. package/scripts/start.sh +30 -0
  808. package/scripts/test.sh +17 -0
  809. package/src/browserless.ts +253 -0
  810. package/src/browsers/cdp-chromium.ts +422 -0
  811. package/src/browsers/index.ts +296 -0
  812. package/src/browsers/playwright-chromium.ts +168 -0
  813. package/src/browsers/playwright-firefox.ts +161 -0
  814. package/src/browsers/playwright-webkit.ts +161 -0
  815. package/src/config.ts +426 -0
  816. package/src/constants.ts +4 -0
  817. package/src/exports.ts +23 -0
  818. package/src/file-system.ts +54 -0
  819. package/src/hooks.ts +37 -0
  820. package/src/http.ts +157 -0
  821. package/src/index.ts +41 -0
  822. package/src/limiter.spec.ts +365 -0
  823. package/src/limiter.ts +225 -0
  824. package/src/metrics.spec.ts +49 -0
  825. package/src/metrics.ts +108 -0
  826. package/src/mime-types.ts +332 -0
  827. package/src/monitoring.ts +53 -0
  828. package/src/routes/chromium/http/content-post.ts +238 -0
  829. package/src/routes/chromium/http/download-post.ts +162 -0
  830. package/src/routes/chromium/http/function-post.ts +98 -0
  831. package/src/routes/chromium/http/pdf-post.ts +234 -0
  832. package/src/routes/chromium/http/performance.ts +71 -0
  833. package/src/routes/chromium/http/scrape-post.ts +439 -0
  834. package/src/routes/chromium/http/screenshot-post.ts +262 -0
  835. package/src/routes/chromium/tests/content.spec.ts +340 -0
  836. package/src/routes/chromium/tests/download.spec.ts +77 -0
  837. package/src/routes/chromium/tests/function.spec.ts +279 -0
  838. package/src/routes/chromium/tests/pdf.spec.ts +375 -0
  839. package/src/routes/chromium/tests/performance.spec.ts +155 -0
  840. package/src/routes/chromium/tests/scrape.spec.ts +414 -0
  841. package/src/routes/chromium/tests/screenshot.spec.ts +387 -0
  842. package/src/routes/chromium/tests/websocket.spec.ts +407 -0
  843. package/src/routes/chromium/utils/function/client.ts +99 -0
  844. package/src/routes/chromium/utils/function/handler.ts +172 -0
  845. package/src/routes/chromium/utils/performance/child.ts +38 -0
  846. package/src/routes/chromium/utils/performance/main.ts +90 -0
  847. package/src/routes/chromium/utils/performance/types.ts +24 -0
  848. package/src/routes/chromium/ws/browser.ts +31 -0
  849. package/src/routes/chromium/ws/cdp-chromium.ts +31 -0
  850. package/src/routes/chromium/ws/page.ts +31 -0
  851. package/src/routes/chromium/ws/playwright-chromium.ts +44 -0
  852. package/src/routes/firefox/tests/websocket.spec.ts +146 -0
  853. package/src/routes/firefox/ws/playwright-firefox.ts +44 -0
  854. package/src/routes/management/http/config-get.ts +82 -0
  855. package/src/routes/management/http/metrics-get.ts +43 -0
  856. package/src/routes/management/http/metrics-total-get.ts +89 -0
  857. package/src/routes/management/http/sessions-get.ts +39 -0
  858. package/src/routes/management/http/static-get.ts +109 -0
  859. package/src/routes/management/tests/management.spec.ts +71 -0
  860. package/src/routes/webkit/tests/websocket.spec.ts +146 -0
  861. package/src/routes/webkit/ws/playwright-webkit.ts +44 -0
  862. package/src/server.ts +609 -0
  863. package/src/shim.spec.ts +154 -0
  864. package/src/shim.ts +78 -0
  865. package/src/types.ts +470 -0
  866. package/src/utils.ts +787 -0
  867. package/src/webhooks.ts +50 -0
  868. package/static/docs/browserless-logo.png +0 -0
  869. package/static/docs/docs.js +2 -0
  870. package/static/docs/index.html +71 -0
  871. package/static/docs/swagger.json +4232 -0
  872. package/static/favicon-32x32.png +0 -0
  873. package/static/function/client.js +31623 -0
  874. package/static/function/index.html +12 -0
  875. package/tsconfig.json +31 -0
@@ -0,0 +1,3028 @@
1
+ /*******************************************************************************
2
+
3
+ uBlock Origin - a browser extension to block requests.
4
+ Copyright (C) 2015-present Raymond Hill
5
+
6
+ This program is free software: you can redistribute it and/or modify
7
+ it under the terms of the GNU General Public License as published by
8
+ the Free Software Foundation, either version 3 of the License, or
9
+ (at your option) any later version.
10
+
11
+ This program is distributed in the hope that it will be useful,
12
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ GNU General Public License for more details.
15
+
16
+ You should have received a copy of the GNU General Public License
17
+ along with this program. If not, see {http://www.gnu.org/licenses/}.
18
+
19
+ Home: https://github.com/gorhill/uBlock
20
+ */
21
+
22
+ 'use strict';
23
+
24
+ import { hostnameFromURI } from './uri-utils.js';
25
+ import { i18n, i18n$ } from './i18n.js';
26
+ import { dom, qs$, qsa$ } from './dom.js';
27
+
28
+ /******************************************************************************/
29
+
30
+ // TODO: fix the inconsistencies re. realm vs. filter source which have
31
+ // accumulated over time.
32
+
33
+ const messaging = vAPI.messaging;
34
+ const logger = self.logger = { ownerId: Date.now() };
35
+ const logDate = new Date();
36
+ const logDateTimezoneOffset = logDate.getTimezoneOffset() * 60000;
37
+ const loggerEntries = [];
38
+
39
+ const COLUMN_TIMESTAMP = 0;
40
+ const COLUMN_FILTER = 1;
41
+ const COLUMN_MESSAGE = 1;
42
+ const COLUMN_RESULT = 2;
43
+ const COLUMN_INITIATOR = 3;
44
+ const COLUMN_PARTYNESS = 4;
45
+ const COLUMN_METHOD = 5;
46
+ const COLUMN_TYPE = 6;
47
+ const COLUMN_URL = 7;
48
+
49
+ let filteredLoggerEntries = [];
50
+ let filteredLoggerEntryVoidedCount = 0;
51
+
52
+ let popupLoggerBox;
53
+ let popupLoggerTooltips;
54
+ let activeTabId = 0;
55
+ let selectedTabId = 0;
56
+ let netInspectorPaused = false;
57
+ let cnameOfEnabled = false;
58
+
59
+ /******************************************************************************/
60
+
61
+ // Various helpers.
62
+
63
+ const tabIdFromPageSelector = logger.tabIdFromPageSelector = function() {
64
+ const value = qs$('#pageSelector').value;
65
+ return value !== '_' ? (parseInt(value, 10) || 0) : activeTabId;
66
+ };
67
+
68
+ const tabIdFromAttribute = function(elem) {
69
+ const value = dom.attr(elem, 'data-tabid') || '';
70
+ const tabId = parseInt(value, 10);
71
+ return isNaN(tabId) ? 0 : tabId;
72
+ };
73
+
74
+
75
+ /******************************************************************************/
76
+ /******************************************************************************/
77
+
78
+ const onStartMovingWidget = (( ) => {
79
+ let widget = null;
80
+ let ondone = null;
81
+ let mx0 = 0, my0 = 0;
82
+ let mx1 = 0, my1 = 0;
83
+ let l0 = 0, t0 = 0;
84
+ let pw = 0, ph = 0;
85
+ let cw = 0, ch = 0;
86
+ let timer;
87
+
88
+ const xyFromEvent = ev => {
89
+ if ( ev.type.startsWith('mouse') ) {
90
+ return { x: ev.pageX, y: ev.pageY };
91
+ }
92
+ const touch = ev.touches[0];
93
+ return { x: touch.pageX, y: touch.pageY };
94
+ };
95
+
96
+ const eatEvent = function(ev) {
97
+ ev.stopPropagation();
98
+ if ( ev.touches !== undefined ) { return; }
99
+ ev.preventDefault();
100
+ };
101
+
102
+ const move = ( ) => {
103
+ timer = undefined;
104
+ const l1 = Math.min(Math.max(l0 + mx1 - mx0, 0), Math.max(pw - cw, 0));
105
+ if ( (l1+cw/2) < (pw/2) ) {
106
+ widget.style.left = `${l1/pw*100}%`;
107
+ widget.style.right = '';
108
+ } else {
109
+ widget.style.right = `${(pw-l1-cw)/pw*100}%`;
110
+ widget.style.left = '';
111
+ }
112
+ const t1 = Math.min(Math.max(t0 + my1 - my0, 0), Math.max(ph - ch, 0));
113
+ widget.style.top = `${t1/ph*100}%`;
114
+ widget.style.bottom = '';
115
+ };
116
+
117
+ const moveAsync = ev => {
118
+ if ( timer !== undefined ) { return; }
119
+ const coord = xyFromEvent(ev);
120
+ mx1 = coord.x; my1 = coord.y;
121
+ timer = self.requestAnimationFrame(move);
122
+ eatEvent(ev);
123
+ };
124
+
125
+ const stop = ev => {
126
+ if ( timer !== undefined ) {
127
+ self.cancelAnimationFrame(timer);
128
+ timer = undefined;
129
+ }
130
+ if ( widget === null ) { return; }
131
+ if ( widget.classList.contains('moving') === false ) { return; }
132
+ widget.classList.remove('moving');
133
+ self.removeEventListener('mousemove', moveAsync, { capture: true });
134
+ self.removeEventListener('touchmove', moveAsync, { capture: true });
135
+ eatEvent(ev);
136
+ widget = null;
137
+ if ( ondone !== null ) {
138
+ ondone();
139
+ ondone = null;
140
+ }
141
+ };
142
+
143
+ return function(ev, target, callback) {
144
+ if ( dom.cl.has(target, 'moving') ) { return; }
145
+ widget = target;
146
+ ondone = callback || null;
147
+ const coord = xyFromEvent(ev);
148
+ mx0 = coord.x; my0 = coord.y;
149
+ const widgetParent = widget.parentElement;
150
+ const crect = widget.getBoundingClientRect();
151
+ const prect = widgetParent.getBoundingClientRect();
152
+ pw = prect.width; ph = prect.height;
153
+ cw = crect.width; ch = crect.height;
154
+ l0 = crect.x - prect.x; t0 = crect.y - prect.y;
155
+ widget.classList.add('moving');
156
+ self.addEventListener('mousemove', moveAsync, { capture: true });
157
+ self.addEventListener('mouseup', stop, { capture: true, once: true });
158
+ self.addEventListener('touchmove', moveAsync, { capture: true });
159
+ self.addEventListener('touchend', stop, { capture: true, once: true });
160
+ eatEvent(ev);
161
+ };
162
+ })();
163
+
164
+ /******************************************************************************/
165
+ /******************************************************************************/
166
+
167
+ // Current design allows for only one modal DOM-based dialog at any given time.
168
+ //
169
+ const modalDialog = (( ) => {
170
+ const overlay = qs$('#modalOverlay');
171
+ const container = qs$('#modalOverlayContainer');
172
+ const closeButton = qs$(overlay, ':scope .closeButton');
173
+ let onDestroyed;
174
+
175
+ const removeChildren = logger.removeAllChildren = function(node) {
176
+ while ( node.firstChild ) {
177
+ node.removeChild(node.firstChild);
178
+ }
179
+ };
180
+
181
+ const create = function(selector, destroyListener) {
182
+ const template = qs$(selector);
183
+ const dialog = dom.clone(template);
184
+ removeChildren(container);
185
+ container.appendChild(dialog);
186
+ onDestroyed = destroyListener;
187
+ return dialog;
188
+ };
189
+
190
+ const show = function() {
191
+ dom.cl.add(overlay, 'on');
192
+ };
193
+
194
+ const destroy = function() {
195
+ dom.cl.remove(overlay, 'on');
196
+ const dialog = container.firstElementChild;
197
+ removeChildren(container);
198
+ if ( typeof onDestroyed === 'function' ) {
199
+ onDestroyed(dialog);
200
+ }
201
+ onDestroyed = undefined;
202
+ };
203
+
204
+ const onClose = function(ev) {
205
+ if ( ev.target === overlay || ev.target === closeButton ) {
206
+ destroy();
207
+ }
208
+ };
209
+ dom.on(overlay, 'click', onClose);
210
+ dom.on(closeButton, 'click', onClose);
211
+
212
+ return { create, show, destroy };
213
+ })();
214
+
215
+ self.logger.modalDialog = modalDialog;
216
+
217
+
218
+ /******************************************************************************/
219
+ /******************************************************************************/
220
+
221
+ const prettyRequestTypes = {
222
+ 'main_frame': 'doc',
223
+ 'stylesheet': 'css',
224
+ 'sub_frame': 'frame',
225
+ 'xmlhttprequest': 'xhr'
226
+ };
227
+
228
+ const uglyRequestTypes = {
229
+ 'doc': 'main_frame',
230
+ 'css': 'stylesheet',
231
+ 'frame': 'sub_frame',
232
+ 'xhr': 'xmlhttprequest'
233
+ };
234
+
235
+ let allTabIds = new Map();
236
+ let allTabIdsToken;
237
+
238
+ /******************************************************************************/
239
+ /******************************************************************************/
240
+
241
+ const regexFromURLFilteringResult = function(result) {
242
+ const beg = result.indexOf(' ');
243
+ const end = result.indexOf(' ', beg + 1);
244
+ const url = result.slice(beg + 1, end);
245
+ if ( url === '*' ) {
246
+ return new RegExp('^.*$', 'gi');
247
+ }
248
+ return new RegExp('^' + url.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
249
+ };
250
+
251
+ /******************************************************************************/
252
+
253
+ // Emphasize hostname in URL, as this is what matters in uMatrix's rules.
254
+
255
+ const nodeFromURL = function(parent, url, re, type) {
256
+ const fragment = document.createDocumentFragment();
257
+ if ( re === undefined ) {
258
+ fragment.textContent = url;
259
+ } else {
260
+ if ( typeof re === 'string' ) {
261
+ re = new RegExp(re.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g');
262
+ }
263
+ const matches = re.exec(url);
264
+ if ( matches === null || matches[0].length === 0 ) {
265
+ fragment.textContent = url;
266
+ } else {
267
+ if ( matches.index !== 0 ) {
268
+ fragment.appendChild(
269
+ document.createTextNode(url.slice(0, matches.index))
270
+ );
271
+ }
272
+ const b = document.createElement('b');
273
+ b.textContent = url.slice(matches.index, re.lastIndex);
274
+ fragment.appendChild(b);
275
+ if ( re.lastIndex !== url.length ) {
276
+ fragment.appendChild(
277
+ document.createTextNode(url.slice(re.lastIndex))
278
+ );
279
+ }
280
+ }
281
+ }
282
+ if ( /^https?:\/\//.test(url) ) {
283
+ const a = document.createElement('a');
284
+ let href = url;
285
+ switch ( type ) {
286
+ case 'css':
287
+ case 'doc':
288
+ case 'frame':
289
+ case 'object':
290
+ case 'other':
291
+ case 'script':
292
+ case 'xhr':
293
+ href = `code-viewer.html?url=${encodeURIComponent(href)}`;
294
+ break;
295
+ default:
296
+ break;
297
+ }
298
+ dom.attr(a, 'href', href);
299
+ dom.attr(a, 'target', '_blank');
300
+ fragment.appendChild(a);
301
+ }
302
+ parent.appendChild(fragment);
303
+ };
304
+
305
+ /******************************************************************************/
306
+
307
+ const padTo2 = function(v) {
308
+ return v < 10 ? '0' + v : v;
309
+ };
310
+
311
+ const normalizeToStr = function(s) {
312
+ return typeof s === 'string' && s !== '' ? s : '';
313
+ };
314
+
315
+ /******************************************************************************/
316
+
317
+ const LogEntry = function(details) {
318
+ if ( details instanceof Object === false ) { return; }
319
+ const receiver = LogEntry.prototype;
320
+ for ( const prop in receiver ) {
321
+ if (
322
+ details.hasOwnProperty(prop) &&
323
+ details[prop] !== receiver[prop]
324
+ ) {
325
+ this[prop] = details[prop];
326
+ }
327
+ }
328
+ if ( details.aliasURL !== undefined ) {
329
+ this.aliased = true;
330
+ }
331
+ if ( this.tabDomain === '' ) {
332
+ this.tabDomain = this.tabHostname || '';
333
+ }
334
+ if ( this.docDomain === '' ) {
335
+ this.docDomain = this.docHostname || '';
336
+ }
337
+ if ( this.domain === '' ) {
338
+ this.domain = details.hostname || '';
339
+ }
340
+ };
341
+ LogEntry.prototype = {
342
+ aliased: false,
343
+ dead: false,
344
+ docDomain: '',
345
+ docHostname: '',
346
+ domain: '',
347
+ filter: undefined,
348
+ id: '',
349
+ method: '',
350
+ realm: '',
351
+ tabDomain: '',
352
+ tabHostname: '',
353
+ tabId: undefined,
354
+ textContent: '',
355
+ tstamp: 0,
356
+ type: '',
357
+ voided: false,
358
+ };
359
+
360
+ /******************************************************************************/
361
+
362
+ const createLogSeparator = function(details, text) {
363
+ const separator = new LogEntry();
364
+ separator.tstamp = details.tstamp;
365
+ separator.realm = 'message';
366
+ separator.tabId = details.tabId;
367
+ separator.type = 'tabLoad';
368
+ separator.textContent = '';
369
+
370
+ const textContent = [];
371
+ logDate.setTime(separator.tstamp - logDateTimezoneOffset);
372
+ textContent.push(
373
+ // cell 0
374
+ padTo2(logDate.getUTCHours()) + ':' +
375
+ padTo2(logDate.getUTCMinutes()) + ':' +
376
+ padTo2(logDate.getSeconds()),
377
+ // cell 1
378
+ text
379
+ );
380
+ separator.textContent = textContent.join('\t');
381
+
382
+ if ( details.voided ) {
383
+ separator.voided = true;
384
+ }
385
+
386
+ return separator;
387
+ };
388
+
389
+ /******************************************************************************/
390
+
391
+ // TODO: once refactoring is mature, consider using push() instead of
392
+ // unshift(). This will require inverting the access logic
393
+ // throughout the code.
394
+ //
395
+ const processLoggerEntries = function(response) {
396
+ const entries = response.entries;
397
+ if ( entries.length === 0 ) { return; }
398
+
399
+ const autoDeleteVoidedRows = qs$('#pageSelector').value === '_';
400
+ const previousCount = filteredLoggerEntries.length;
401
+
402
+ for ( const entry of entries ) {
403
+ const unboxed = JSON.parse(entry);
404
+ if ( unboxed.filter instanceof Object ){
405
+ loggerStats.processFilter(unboxed.filter);
406
+ }
407
+ if ( netInspectorPaused ) { continue; }
408
+ const parsed = parseLogEntry(unboxed);
409
+ if (
410
+ parsed.tabId !== undefined &&
411
+ allTabIds.has(parsed.tabId) === false
412
+ ) {
413
+ if ( autoDeleteVoidedRows ) { continue; }
414
+ parsed.voided = true;
415
+ }
416
+ if (
417
+ parsed.type === 'main_frame' &&
418
+ parsed.aliased === false && (
419
+ parsed.filter === undefined ||
420
+ parsed.filter.modifier !== true
421
+ )
422
+ ) {
423
+ const separator = createLogSeparator(parsed, unboxed.url);
424
+ loggerEntries.unshift(separator);
425
+ if ( rowFilterer.filterOne(separator) ) {
426
+ filteredLoggerEntries.unshift(separator);
427
+ if ( separator.voided ) {
428
+ filteredLoggerEntryVoidedCount += 1;
429
+ }
430
+ }
431
+ }
432
+ if ( cnameOfEnabled === false && parsed.aliased ) {
433
+ qs$('#filterExprCnameOf').style.display = '';
434
+ cnameOfEnabled = true;
435
+ }
436
+ loggerEntries.unshift(parsed);
437
+ if ( rowFilterer.filterOne(parsed) ) {
438
+ filteredLoggerEntries.unshift(parsed);
439
+ if ( parsed.voided ) {
440
+ filteredLoggerEntryVoidedCount += 1;
441
+ }
442
+ }
443
+ }
444
+
445
+ const addedCount = filteredLoggerEntries.length - previousCount;
446
+ if ( addedCount !== 0 ) {
447
+ viewPort.updateContent(addedCount);
448
+ rowJanitor.inserted(addedCount);
449
+ }
450
+ };
451
+
452
+ /******************************************************************************/
453
+
454
+ const parseLogEntry = function(details) {
455
+ // Patch realm until changed all over codebase to make this unnecessary
456
+ if ( details.realm === 'cosmetic' ) {
457
+ details.realm = 'extended';
458
+ }
459
+
460
+ const entry = new LogEntry(details);
461
+
462
+ // Assemble the text content, i.e. the pre-built string which will be
463
+ // used to match logger output filtering expressions.
464
+ const textContent = [];
465
+
466
+ // Cell 0
467
+ logDate.setTime(details.tstamp - logDateTimezoneOffset);
468
+ textContent.push(
469
+ padTo2(logDate.getUTCHours()) + ':' +
470
+ padTo2(logDate.getUTCMinutes()) + ':' +
471
+ padTo2(logDate.getSeconds())
472
+ );
473
+
474
+ // Cell 1
475
+ if ( details.realm === 'message' ) {
476
+ textContent.push(details.text);
477
+ entry.textContent = textContent.join('\t');
478
+ return entry;
479
+ }
480
+
481
+ // Cell 1, 2
482
+ if ( entry.filter !== undefined ) {
483
+ textContent.push(entry.filter.raw);
484
+ if ( entry.filter.result === 1 ) {
485
+ textContent.push('--');
486
+ } else if ( entry.filter.result === 2 ) {
487
+ textContent.push('++');
488
+ } else if ( entry.filter.result === 3 ) {
489
+ textContent.push('**');
490
+ } else if ( entry.filter.source === 'redirect' ) {
491
+ textContent.push('<<');
492
+ } else {
493
+ textContent.push('');
494
+ }
495
+ } else {
496
+ textContent.push('', '');
497
+ }
498
+
499
+ // Cell 3
500
+ textContent.push(normalizeToStr(entry.docHostname));
501
+
502
+ // Cell 4: partyness
503
+ if (
504
+ entry.realm === 'network' &&
505
+ typeof entry.domain === 'string' &&
506
+ entry.domain !== ''
507
+ ) {
508
+ let partyness = '';
509
+ if ( entry.tabDomain !== undefined ) {
510
+ if ( entry.tabId < 0 ) {
511
+ partyness += '0,';
512
+ }
513
+ partyness += entry.domain === entry.tabDomain ? '1' : '3';
514
+ } else {
515
+ partyness += '?';
516
+ }
517
+ if ( entry.docDomain !== entry.tabDomain ) {
518
+ partyness += ',';
519
+ if ( entry.docDomain !== undefined ) {
520
+ partyness += entry.domain === entry.docDomain ? '1' : '3';
521
+ } else {
522
+ partyness += '?';
523
+ }
524
+ }
525
+ textContent.push(partyness);
526
+ } else {
527
+ textContent.push('');
528
+ }
529
+
530
+ // Cell 5: method
531
+ textContent.push(entry.method || '');
532
+
533
+ // Cell 6
534
+ textContent.push(
535
+ normalizeToStr(prettyRequestTypes[entry.type] || entry.type)
536
+ );
537
+
538
+ // Cell 7
539
+ textContent.push(normalizeToStr(details.url));
540
+
541
+ // Hidden cells -- useful for row-filtering purpose
542
+
543
+ // Cell 8
544
+ if ( entry.aliased ) {
545
+ textContent.push(`aliasURL=${details.aliasURL}`);
546
+ }
547
+
548
+ entry.textContent = textContent.join('\t');
549
+ return entry;
550
+ };
551
+
552
+ /******************************************************************************/
553
+
554
+ const viewPort = (( ) => {
555
+ const vwRenderer = qs$('#vwRenderer');
556
+ const vwScroller = qs$('#vwScroller');
557
+ const vwVirtualContent = qs$('#vwVirtualContent');
558
+ const vwContent = qs$('#vwContent');
559
+ const vwLineSizer = qs$('#vwLineSizer');
560
+ const vwLogEntryTemplate = qs$('#logEntryTemplate > div');
561
+ const vwEntries = [];
562
+
563
+ const detailableRealms = new Set([ 'network', 'extended' ]);
564
+
565
+ let vwHeight = 0;
566
+ let lineHeight = 0;
567
+ let wholeHeight = 0;
568
+ let lastTopPix = 0;
569
+ let lastTopRow = 0;
570
+
571
+ const ViewEntry = function() {
572
+ this.div = document.createElement('div');
573
+ this.div.className = 'logEntry';
574
+ vwContent.appendChild(this.div);
575
+ this.logEntry = undefined;
576
+ };
577
+ ViewEntry.prototype = {
578
+ dispose: function() {
579
+ vwContent.removeChild(this.div);
580
+ },
581
+ };
582
+
583
+ const rowFromScrollTopPix = function(px) {
584
+ return lineHeight !== 0 ? Math.floor(px / lineHeight) : 0;
585
+ };
586
+
587
+ // This is called when the browser fired scroll events
588
+ const onScrollChanged = function() {
589
+ const newScrollTopPix = vwScroller.scrollTop;
590
+ const delta = newScrollTopPix - lastTopPix;
591
+ if ( delta === 0 ) { return; }
592
+ lastTopPix = newScrollTopPix;
593
+ if ( filteredLoggerEntries.length <= 2 ) { return; }
594
+ // No entries were rolled = all entries keep their current details
595
+ if ( rollLines(rowFromScrollTopPix(newScrollTopPix)) ) {
596
+ fillLines();
597
+ }
598
+ positionLines();
599
+ vwContent.style.top = `${lastTopPix}px`;
600
+ };
601
+
602
+ // Coalesce scroll events
603
+ const scrollTimer = vAPI.defer.create(onScrollChanged);
604
+ const onScroll = ( ) => {
605
+ scrollTimer.onvsync(1000/32);
606
+ };
607
+ dom.on(vwScroller, 'scroll', onScroll, { passive: true });
608
+
609
+ const onLayoutChanged = function() {
610
+ vwHeight = vwRenderer.clientHeight;
611
+ vwContent.style.height = `${vwScroller.clientHeight}px`;
612
+
613
+ const vExpanded =
614
+ dom.cl.has('#netInspector .vCompactToggler', 'vExpanded');
615
+
616
+ let newLineHeight = qs$(vwLineSizer, '.oneLine').clientHeight;
617
+
618
+ if ( vExpanded ) {
619
+ newLineHeight *= loggerSettings.linesPerEntry;
620
+ }
621
+
622
+ const lineCount = newLineHeight !== 0
623
+ ? Math.ceil(vwHeight / newLineHeight) + 1
624
+ : 0;
625
+ if ( lineCount > vwEntries.length ) {
626
+ do {
627
+ vwEntries.push(new ViewEntry());
628
+ } while ( lineCount > vwEntries.length );
629
+ } else if ( lineCount < vwEntries.length ) {
630
+ do {
631
+ vwEntries.pop().dispose();
632
+ } while ( lineCount < vwEntries.length );
633
+ }
634
+
635
+ const cellWidths = Array.from(
636
+ qsa$(vwLineSizer, '.oneLine span')
637
+ ).map((el, i) => {
638
+ return loggerSettings.columns[i] !== false
639
+ ? el.clientWidth + 1
640
+ : 0;
641
+ });
642
+ const reservedWidth =
643
+ cellWidths[COLUMN_TIMESTAMP] +
644
+ cellWidths[COLUMN_RESULT] +
645
+ cellWidths[COLUMN_PARTYNESS] +
646
+ cellWidths[COLUMN_METHOD] +
647
+ cellWidths[COLUMN_TYPE];
648
+ cellWidths[COLUMN_URL] = 0.5;
649
+ if ( cellWidths[COLUMN_FILTER] === 0 && cellWidths[COLUMN_INITIATOR] === 0 ) {
650
+ cellWidths[COLUMN_URL] = 1;
651
+ } else if ( cellWidths[COLUMN_FILTER] === 0 ) {
652
+ cellWidths[COLUMN_INITIATOR] = 0.35;
653
+ cellWidths[COLUMN_URL] = 0.65;
654
+ } else if ( cellWidths[COLUMN_INITIATOR] === 0 ) {
655
+ cellWidths[COLUMN_FILTER] = 0.35;
656
+ cellWidths[COLUMN_URL] = 0.65;
657
+ } else {
658
+ cellWidths[COLUMN_FILTER] = 0.25;
659
+ cellWidths[COLUMN_INITIATOR] = 0.25;
660
+ cellWidths[COLUMN_URL] = 0.5;
661
+ }
662
+ const style = qs$('#vwRendererRuntimeStyles');
663
+ const cssRules = [
664
+ '#vwContent .logEntry {',
665
+ ` height: ${newLineHeight}px;`,
666
+ '}',
667
+ `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_TIMESTAMP+1}) {`,
668
+ ` width: ${cellWidths[COLUMN_TIMESTAMP]}px;`,
669
+ '}',
670
+ `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_FILTER+1}) {`,
671
+ ` width: calc(calc(100% - ${reservedWidth}px) * ${cellWidths[COLUMN_FILTER]});`,
672
+ '}',
673
+ `#vwContent .logEntry > div.messageRealm > span:nth-of-type(${COLUMN_MESSAGE+1}) {`,
674
+ ` width: calc(100% - ${cellWidths[COLUMN_MESSAGE]}px);`,
675
+ '}',
676
+ `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_RESULT+1}) {`,
677
+ ` width: ${cellWidths[COLUMN_RESULT]}px;`,
678
+ '}',
679
+ `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_INITIATOR+1}) {`,
680
+ ` width: calc(calc(100% - ${reservedWidth}px) * ${cellWidths[COLUMN_INITIATOR]});`,
681
+ '}',
682
+ `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_PARTYNESS+1}) {`,
683
+ ` width: ${cellWidths[COLUMN_PARTYNESS]}px;`,
684
+ '}',
685
+ `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_METHOD+1}) {`,
686
+ ` width: ${cellWidths[COLUMN_METHOD]}px;`,
687
+ '}',
688
+ `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_TYPE+1}) {`,
689
+ ` width: ${cellWidths[COLUMN_TYPE]}px;`,
690
+ '}',
691
+ `#vwContent .logEntry > div > span:nth-of-type(${COLUMN_URL+1}) {`,
692
+ ` width: calc(calc(100% - ${reservedWidth}px) * ${cellWidths[COLUMN_URL]});`,
693
+ '}',
694
+ '',
695
+ ];
696
+ for ( let i = 0; i < cellWidths.length; i++ ) {
697
+ if ( cellWidths[i] !== 0 ) { continue; }
698
+ cssRules.push(
699
+ `#vwContent .logEntry > div > span:nth-of-type(${i + 1}) {`,
700
+ ' display: none;',
701
+ '}'
702
+ );
703
+ }
704
+ style.textContent = cssRules.join('\n');
705
+
706
+ lineHeight = newLineHeight;
707
+ positionLines();
708
+ dom.cl.toggle('#netInspector', 'vExpanded', vExpanded);
709
+
710
+ updateContent(0);
711
+ };
712
+
713
+ const resizeTimer = vAPI.defer.create(onLayoutChanged);
714
+ const updateLayout = function() {
715
+ resizeTimer.onvsync(1000/8);
716
+ };
717
+ dom.on(window, 'resize', updateLayout, { passive: true });
718
+
719
+ updateLayout();
720
+
721
+ const renderFilterToSpan = function(span, filter) {
722
+ if ( filter.charCodeAt(0) !== 0x23 /* '#' */ ) { return false; }
723
+ const match = /^#@?#/.exec(filter);
724
+ if ( match === null ) { return false; }
725
+ let child = document.createElement('span');
726
+ child.textContent = match[0];
727
+ span.appendChild(child);
728
+ child = document.createElement('span');
729
+ child.textContent = filter.slice(match[0].length);
730
+ span.appendChild(child);
731
+ return true;
732
+ };
733
+
734
+ const renderToDiv = function(vwEntry, i) {
735
+ if ( i >= filteredLoggerEntries.length ) {
736
+ vwEntry.logEntry = undefined;
737
+ return null;
738
+ }
739
+
740
+ const details = filteredLoggerEntries[i];
741
+ if ( vwEntry.logEntry === details ) {
742
+ return vwEntry.div.firstElementChild;
743
+ }
744
+
745
+ vwEntry.logEntry = details;
746
+
747
+ const cells = details.textContent.split('\t');
748
+ const div = dom.clone(vwLogEntryTemplate);
749
+ const divcl = div.classList;
750
+ let span;
751
+
752
+ // Realm
753
+ if ( details.realm !== undefined ) {
754
+ divcl.add(details.realm + 'Realm');
755
+ }
756
+
757
+ // Timestamp
758
+ span = div.children[COLUMN_TIMESTAMP];
759
+ span.textContent = cells[COLUMN_TIMESTAMP];
760
+
761
+ // Tab id
762
+ if ( details.tabId !== undefined ) {
763
+ dom.attr(div, 'data-tabid', details.tabId);
764
+ if ( details.voided ) {
765
+ divcl.add('voided');
766
+ }
767
+ }
768
+
769
+ if ( details.realm === 'message' ) {
770
+ if ( details.type !== undefined ) {
771
+ dom.attr(div, 'data-type', details.type);
772
+ }
773
+ span = div.children[COLUMN_MESSAGE];
774
+ span.textContent = cells[COLUMN_MESSAGE];
775
+ return div;
776
+ }
777
+
778
+ if ( detailableRealms.has(details.realm) ) {
779
+ divcl.add('canDetails');
780
+ }
781
+
782
+ // Filter
783
+ const filter = details.filter || undefined;
784
+ let filteringType;
785
+ if ( filter !== undefined ) {
786
+ if ( typeof filter.source === 'string' ) {
787
+ filteringType = filter.source;
788
+ }
789
+ if ( filteringType === 'static' ) {
790
+ divcl.add('canLookup');
791
+ } else if ( details.realm === 'extended' ) {
792
+ divcl.toggle('canLookup', /^#@?#/.test(filter.raw));
793
+ divcl.toggle('isException', filter.raw.startsWith('#@#'));
794
+ }
795
+ if ( filter.modifier === true ) {
796
+ dom.attr(div, 'data-modifier', '');
797
+ }
798
+ }
799
+ span = div.children[COLUMN_FILTER];
800
+ if ( renderFilterToSpan(span, cells[COLUMN_FILTER]) ) {
801
+ if ( /^\+js\(.*\)$/.test(span.children[1].textContent) ) {
802
+ divcl.add('scriptlet');
803
+ }
804
+ } else {
805
+ span.textContent = cells[COLUMN_FILTER];
806
+ }
807
+
808
+ // Event
809
+ if ( cells[COLUMN_RESULT] === '--' ) {
810
+ dom.attr(div, 'data-status', '1');
811
+ } else if ( cells[COLUMN_RESULT] === '++' ) {
812
+ dom.attr(div, 'data-status', '2');
813
+ } else if ( cells[COLUMN_RESULT] === '**' ) {
814
+ dom.attr(div, 'data-status', '3');
815
+ } else if ( cells[COLUMN_RESULT] === '<<' ) {
816
+ divcl.add('redirect');
817
+ }
818
+ span = div.children[COLUMN_RESULT];
819
+ span.textContent = cells[COLUMN_RESULT];
820
+
821
+ // Origins
822
+ if ( details.tabHostname ) {
823
+ dom.attr(div, 'data-tabhn', details.tabHostname);
824
+ }
825
+ if ( details.docHostname ) {
826
+ dom.attr(div, 'data-dochn', details.docHostname);
827
+ }
828
+ span = div.children[COLUMN_INITIATOR];
829
+ span.textContent = cells[COLUMN_INITIATOR];
830
+
831
+ // Partyness
832
+ if (
833
+ cells[COLUMN_PARTYNESS] !== '' &&
834
+ details.realm === 'network' &&
835
+ details.domain !== undefined
836
+ ) {
837
+ let text = `${details.tabDomain}`;
838
+ if ( details.docDomain !== details.tabDomain ) {
839
+ text += ` \u22ef ${details.docDomain}`;
840
+ }
841
+ text += ` \u21d2 ${details.domain}`;
842
+ dom.attr(div, 'data-parties', text);
843
+ }
844
+ span = div.children[COLUMN_PARTYNESS];
845
+ span.textContent = cells[COLUMN_PARTYNESS];
846
+
847
+ // Method
848
+ span = div.children[COLUMN_METHOD];
849
+ span.textContent = cells[COLUMN_METHOD];
850
+
851
+ // Type
852
+ span = div.children[COLUMN_TYPE];
853
+ span.textContent = cells[COLUMN_TYPE];
854
+
855
+ // URL
856
+ let re;
857
+ if ( filteringType === 'static' ) {
858
+ re = new RegExp(filter.regex, 'gi');
859
+ } else if ( filteringType === 'dynamicUrl' ) {
860
+ re = regexFromURLFilteringResult(filter.rule.join(' '));
861
+ }
862
+ nodeFromURL(div.children[COLUMN_URL], cells[COLUMN_URL], re, cells[COLUMN_TYPE]);
863
+
864
+ // Alias URL (CNAME, etc.)
865
+ if ( cells.length > 8 ) {
866
+ const pos = details.textContent.lastIndexOf('\taliasURL=');
867
+ if ( pos !== -1 ) {
868
+ dom.attr(div, 'data-aliasid', details.id);
869
+ }
870
+ }
871
+
872
+ return div;
873
+ };
874
+
875
+ // The idea is that positioning DOM elements is faster than
876
+ // removing/inserting DOM elements.
877
+ const positionLines = function() {
878
+ if ( lineHeight === 0 ) { return; }
879
+ let y = -(lastTopPix % lineHeight);
880
+ for ( const vwEntry of vwEntries ) {
881
+ vwEntry.div.style.top = `${y}px`;
882
+ y += lineHeight;
883
+ }
884
+ };
885
+
886
+ const rollLines = function(topRow) {
887
+ let delta = topRow - lastTopRow;
888
+ let deltaLength = Math.abs(delta);
889
+ // No point rolling if no rows can be reused
890
+ if ( deltaLength > 0 && deltaLength < vwEntries.length ) {
891
+ if ( delta < 0 ) { // Move bottom rows to the top
892
+ vwEntries.unshift(...vwEntries.splice(delta));
893
+ } else { // Move top rows to the bottom
894
+ vwEntries.push(...vwEntries.splice(0, delta));
895
+ }
896
+ }
897
+ lastTopRow = topRow;
898
+ return delta;
899
+ };
900
+
901
+ const fillLines = function() {
902
+ let rowBeg = lastTopRow;
903
+ for ( const vwEntry of vwEntries ) {
904
+ const newDiv = renderToDiv(vwEntry, rowBeg);
905
+ const container = vwEntry.div;
906
+ const oldDiv = container.firstElementChild;
907
+ if ( newDiv !== null ) {
908
+ if ( oldDiv === null ) {
909
+ container.appendChild(newDiv);
910
+ } else if ( newDiv !== oldDiv ) {
911
+ container.removeChild(oldDiv);
912
+ container.appendChild(newDiv);
913
+ }
914
+ } else if ( oldDiv !== null ) {
915
+ container.removeChild(oldDiv);
916
+ }
917
+ rowBeg += 1;
918
+ }
919
+ };
920
+
921
+ const contentChanged = function(addedCount) {
922
+ lastTopRow += addedCount;
923
+ const newWholeHeight = Math.max(
924
+ filteredLoggerEntries.length * lineHeight,
925
+ vwRenderer.clientHeight
926
+ );
927
+ if ( newWholeHeight !== wholeHeight ) {
928
+ vwVirtualContent.style.height = `${newWholeHeight}px`;
929
+ wholeHeight = newWholeHeight;
930
+ }
931
+ };
932
+
933
+ const updateContent = function(addedCount) {
934
+ contentChanged(addedCount);
935
+ // Content changed
936
+ if ( addedCount === 0 ) {
937
+ if (
938
+ lastTopRow !== 0 &&
939
+ lastTopRow + vwEntries.length > filteredLoggerEntries.length
940
+ ) {
941
+ lastTopRow = filteredLoggerEntries.length - vwEntries.length;
942
+ if ( lastTopRow < 0 ) { lastTopRow = 0; }
943
+ lastTopPix = lastTopRow * lineHeight;
944
+ vwContent.style.top = `${lastTopPix}px`;
945
+ vwScroller.scrollTop = lastTopPix;
946
+ positionLines();
947
+ }
948
+ fillLines();
949
+ return;
950
+ }
951
+
952
+ // Content added
953
+ // Preserve scroll position
954
+ if ( lastTopPix === 0 ) {
955
+ rollLines(0);
956
+ positionLines();
957
+ fillLines();
958
+ return;
959
+ }
960
+
961
+ // Preserve row position
962
+ lastTopPix += lineHeight * addedCount;
963
+ vwContent.style.top = `${lastTopPix}px`;
964
+ vwScroller.scrollTop = lastTopPix;
965
+ };
966
+
967
+ return { updateContent, updateLayout, };
968
+ })();
969
+
970
+ /******************************************************************************/
971
+
972
+ const updateCurrentTabTitle = (( ) => {
973
+ const i18nCurrentTab = i18n$('loggerCurrentTab');
974
+
975
+ return function() {
976
+ const select = qs$('#pageSelector');
977
+ if ( select.value !== '_' || activeTabId === 0 ) { return; }
978
+ const opt0 = qs$(select, '[value="_"]');
979
+ const opt1 = qs$(select, `[value="${activeTabId}"]`);
980
+ let text = i18nCurrentTab;
981
+ if ( opt1 !== null ) {
982
+ text += ' / ' + opt1.textContent;
983
+ }
984
+ opt0.textContent = text;
985
+ };
986
+ })();
987
+
988
+ /******************************************************************************/
989
+
990
+ const synchronizeTabIds = function(newTabIds) {
991
+ const select = qs$('#pageSelector');
992
+ const selectedTabValue = select.value;
993
+ const oldTabIds = allTabIds;
994
+
995
+ // Collate removed tab ids.
996
+ const toVoid = new Set();
997
+ for ( const tabId of oldTabIds.keys() ) {
998
+ if ( newTabIds.has(tabId) ) { continue; }
999
+ toVoid.add(tabId);
1000
+ }
1001
+ allTabIds = newTabIds;
1002
+
1003
+ // Mark as "void" all logger entries which are linked to now invalid
1004
+ // tab ids.
1005
+ // When an entry is voided without being removed, we re-create a new entry
1006
+ // in order to ensure the entry has a new identity. A new identify ensures
1007
+ // that identity-based associations elsewhere are automatically
1008
+ // invalidated.
1009
+ if ( toVoid.size !== 0 ) {
1010
+ const autoDeleteVoidedRows = selectedTabValue === '_';
1011
+ let rowVoided = false;
1012
+ for ( let i = 0, n = loggerEntries.length; i < n; i++ ) {
1013
+ const entry = loggerEntries[i];
1014
+ if ( toVoid.has(entry.tabId) === false ) { continue; }
1015
+ if ( entry.voided ) { continue; }
1016
+ rowVoided = entry.voided = true;
1017
+ if ( autoDeleteVoidedRows ) {
1018
+ entry.dead = true;
1019
+ }
1020
+ loggerEntries[i] = new LogEntry(entry);
1021
+ }
1022
+ if ( rowVoided ) {
1023
+ rowFilterer.filterAll();
1024
+ }
1025
+ }
1026
+
1027
+ // Remove popup if it is currently bound to a removed tab.
1028
+ if ( toVoid.has(popupManager.tabId) ) {
1029
+ popupManager.toggleOff();
1030
+ }
1031
+
1032
+ const tabIds = Array.from(newTabIds.keys()).sort(function(a, b) {
1033
+ return newTabIds.get(a).localeCompare(newTabIds.get(b));
1034
+ });
1035
+ let j = 3;
1036
+ for ( let i = 0; i < tabIds.length; i++ ) {
1037
+ const tabId = tabIds[i];
1038
+ if ( tabId <= 0 ) { continue; }
1039
+ if ( j === select.options.length ) {
1040
+ select.appendChild(document.createElement('option'));
1041
+ }
1042
+ const option = select.options[j];
1043
+ // Truncate too long labels.
1044
+ option.textContent = newTabIds.get(tabId).slice(0, 80);
1045
+ dom.attr(option, 'value', tabId);
1046
+ if ( option.value === selectedTabValue ) {
1047
+ select.selectedIndex = j;
1048
+ dom.attr(option, 'selected', '');
1049
+ } else {
1050
+ dom.attr(option, 'selected', null);
1051
+ }
1052
+ j += 1;
1053
+ }
1054
+ while ( j < select.options.length ) {
1055
+ select.removeChild(select.options[j]);
1056
+ }
1057
+ if ( select.value !== selectedTabValue ) {
1058
+ select.selectedIndex = 0;
1059
+ select.value = '';
1060
+ dom.attr(select.options[0], 'selected', '');
1061
+ pageSelectorChanged();
1062
+ }
1063
+
1064
+ updateCurrentTabTitle();
1065
+ };
1066
+
1067
+ /******************************************************************************/
1068
+
1069
+ const onLogBufferRead = function(response) {
1070
+ if ( !response || response.unavailable ) { return; }
1071
+
1072
+ // Disable tooltips?
1073
+ if (
1074
+ popupLoggerTooltips === undefined &&
1075
+ response.tooltips !== undefined
1076
+ ) {
1077
+ popupLoggerTooltips = response.tooltips;
1078
+ if ( popupLoggerTooltips === false ) {
1079
+ dom.attr('[data-i18n-title]', 'title', '');
1080
+ }
1081
+ }
1082
+
1083
+ // Tab id of currently active tab
1084
+ let activeTabIdChanged = false;
1085
+ if ( response.activeTabId ) {
1086
+ activeTabIdChanged = response.activeTabId !== activeTabId;
1087
+ activeTabId = response.activeTabId;
1088
+ }
1089
+
1090
+ if ( Array.isArray(response.tabIds) ) {
1091
+ response.tabIds = new Map(response.tabIds);
1092
+ }
1093
+
1094
+ // List of tab ids has changed
1095
+ if ( response.tabIds !== undefined ) {
1096
+ synchronizeTabIds(response.tabIds);
1097
+ allTabIdsToken = response.tabIdsToken;
1098
+ }
1099
+
1100
+ if ( activeTabIdChanged ) {
1101
+ pageSelectorFromURLHash();
1102
+ }
1103
+
1104
+ processLoggerEntries(response);
1105
+
1106
+ // Synchronize DOM with sent logger data
1107
+ dom.cl.toggle(dom.html, 'colorBlind', response.colorBlind === true);
1108
+ dom.cl.toggle('#clean', 'disabled', filteredLoggerEntryVoidedCount === 0);
1109
+ dom.cl.toggle('#clear', 'disabled', filteredLoggerEntries.length === 0);
1110
+ };
1111
+
1112
+ /******************************************************************************/
1113
+
1114
+ const readLogBuffer = (( ) => {
1115
+ let reading = false;
1116
+
1117
+ const readLogBufferNow = async function() {
1118
+ if ( logger.ownerId === undefined ) { return; }
1119
+ if ( reading ) { return; }
1120
+
1121
+ reading = true;
1122
+
1123
+ const msg = {
1124
+ what: 'readAll',
1125
+ ownerId: logger.ownerId,
1126
+ tabIdsToken: allTabIdsToken,
1127
+ };
1128
+
1129
+ // This is to detect changes in the position or size of the logger
1130
+ // popup window (if in use).
1131
+ if (
1132
+ popupLoggerBox instanceof Object &&
1133
+ (
1134
+ self.screenX !== popupLoggerBox.x ||
1135
+ self.screenY !== popupLoggerBox.y ||
1136
+ self.outerWidth !== popupLoggerBox.w ||
1137
+ self.outerHeight !== popupLoggerBox.h
1138
+ )
1139
+ ) {
1140
+ popupLoggerBox.x = self.screenX;
1141
+ popupLoggerBox.y = self.screenY;
1142
+ popupLoggerBox.w = self.outerWidth;
1143
+ popupLoggerBox.h = self.outerHeight;
1144
+ msg.popupLoggerBoxChanged = true;
1145
+ }
1146
+
1147
+ const response = await vAPI.messaging.send('loggerUI', msg);
1148
+
1149
+ onLogBufferRead(response);
1150
+
1151
+ reading = false;
1152
+
1153
+ timer.on(1200);
1154
+ };
1155
+
1156
+ const timer = vAPI.defer.create(readLogBufferNow);
1157
+
1158
+ readLogBufferNow();
1159
+
1160
+ return ( ) => {
1161
+ timer.on(1200);
1162
+ };
1163
+ })();
1164
+
1165
+ /******************************************************************************/
1166
+
1167
+ const pageSelectorChanged = function() {
1168
+ const select = qs$('#pageSelector');
1169
+ window.location.replace('#' + select.value);
1170
+ pageSelectorFromURLHash();
1171
+ };
1172
+
1173
+ const pageSelectorFromURLHash = (( ) => {
1174
+ let lastHash;
1175
+ let lastSelectedTabId;
1176
+
1177
+ return function() {
1178
+ let hash = window.location.hash.slice(1);
1179
+ let match = /^([^+]+)\+(.+)$/.exec(hash);
1180
+ if ( match !== null ) {
1181
+ hash = match[1];
1182
+ activeTabId = parseInt(match[2], 10) || 0;
1183
+ window.location.hash = '#' + hash;
1184
+ }
1185
+
1186
+ if ( hash !== lastHash ) {
1187
+ const select = qs$('#pageSelector');
1188
+ let option = qs$(select, `option[value="${hash}"]`);
1189
+ if ( option === null ) {
1190
+ hash = '0';
1191
+ option = select.options[0];
1192
+ }
1193
+ select.selectedIndex = option.index;
1194
+ select.value = option.value;
1195
+ lastHash = hash;
1196
+ }
1197
+
1198
+ selectedTabId = hash === '_'
1199
+ ? activeTabId
1200
+ : parseInt(hash, 10) || 0;
1201
+
1202
+ if ( lastSelectedTabId === selectedTabId ) { return; }
1203
+
1204
+ rowFilterer.filterAll();
1205
+ document.dispatchEvent(new Event('tabIdChanged'));
1206
+ updateCurrentTabTitle();
1207
+ dom.cl.toggle('.needdom', 'disabled', selectedTabId <= 0);
1208
+ dom.cl.toggle('.needscope', 'disabled', selectedTabId <= 0);
1209
+ lastSelectedTabId = selectedTabId;
1210
+ };
1211
+ })();
1212
+
1213
+ /******************************************************************************/
1214
+
1215
+ const reloadTab = function(bypassCache = false) {
1216
+ const tabId = tabIdFromPageSelector();
1217
+ if ( tabId <= 0 ) { return; }
1218
+ messaging.send('loggerUI', {
1219
+ what: 'reloadTab',
1220
+ tabId,
1221
+ bypassCache,
1222
+ });
1223
+ };
1224
+
1225
+ dom.on('#refresh', 'click', ev => {
1226
+ reloadTab(ev.ctrlKey || ev.metaKey || ev.shiftKey);
1227
+ });
1228
+
1229
+ dom.on(document, 'keydown', ev => {
1230
+ if ( ev.isComposing ) { return; }
1231
+ let bypassCache = false;
1232
+ switch ( ev.key ) {
1233
+ case 'F5':
1234
+ bypassCache = ev.ctrlKey || ev.metaKey || ev.shiftKey;
1235
+ break;
1236
+ case 'r':
1237
+ if ( (ev.ctrlKey || ev.metaKey) !== true ) { return; }
1238
+ break;
1239
+ case 'R':
1240
+ if ( (ev.ctrlKey || ev.metaKey) !== true ) { return; }
1241
+ bypassCache = true;
1242
+ break;
1243
+ default:
1244
+ return;
1245
+ }
1246
+ reloadTab(bypassCache);
1247
+ ev.preventDefault();
1248
+ ev.stopPropagation();
1249
+ }, { capture: true });
1250
+
1251
+ /******************************************************************************/
1252
+ /******************************************************************************/
1253
+
1254
+ (( ) => {
1255
+ const reRFC3986 = /^([^:\/?#]+:)?(\/\/[^\/?#]*)?([^?#]*)(\?[^#]*)?(#.*)?/;
1256
+ const reSchemeOnly = /^[\w-]+:$/;
1257
+ const staticFilterTypes = {
1258
+ 'beacon': 'ping',
1259
+ 'doc': 'document',
1260
+ 'css': 'stylesheet',
1261
+ 'frame': 'subdocument',
1262
+ 'object_subrequest': 'object',
1263
+ 'csp_report': 'other',
1264
+ };
1265
+ const createdStaticFilters = {};
1266
+ const reIsExceptionFilter = /^@@|^[\w.-]*?#@#/;
1267
+
1268
+ let dialog = null;
1269
+ let targetRow = null;
1270
+ let targetType;
1271
+ let targetURLs = [];
1272
+ let targetFrameHostname;
1273
+ let targetPageHostname;
1274
+ let targetTabId;
1275
+ let targetDomain;
1276
+ let targetPageDomain;
1277
+ let targetFrameDomain;
1278
+
1279
+ const uglyTypeFromSelector = pane => {
1280
+ const prettyType = selectValue('select.type.' + pane);
1281
+ if ( pane === 'static' ) {
1282
+ return staticFilterTypes[prettyType] || prettyType;
1283
+ }
1284
+ return uglyRequestTypes[prettyType] || prettyType;
1285
+ };
1286
+
1287
+ const selectNode = selector => {
1288
+ return qs$(dialog, selector);
1289
+ };
1290
+
1291
+ const selectValue = selector => {
1292
+ return selectNode(selector).value || '';
1293
+ };
1294
+
1295
+ const staticFilterNode = ( ) => {
1296
+ return qs$(dialog, 'div.panes > div.static textarea');
1297
+ };
1298
+
1299
+ const toExceptionFilter = (filter, extended) => {
1300
+ if ( reIsExceptionFilter.test(filter) ) { return filter; }
1301
+ return extended ? filter.replace('##', '#@#') : `@@${filter}`;
1302
+ };
1303
+
1304
+ const onColorsReady = function(response) {
1305
+ dom.cl.toggle(dom.body, 'dirty', response.dirty);
1306
+ for ( const url in response.colors ) {
1307
+ if ( response.colors.hasOwnProperty(url) === false ) { continue; }
1308
+ const colorEntry = response.colors[url];
1309
+ const node = qs$(dialog, `.dynamic .entry .action[data-url="${url}"]`);
1310
+ if ( node === null ) { continue; }
1311
+ dom.cl.toggle(node, 'allow', colorEntry.r === 2);
1312
+ dom.cl.toggle(node, 'noop', colorEntry.r === 3);
1313
+ dom.cl.toggle(node, 'block', colorEntry.r === 1);
1314
+ dom.cl.toggle(node, 'own', colorEntry.own);
1315
+ }
1316
+ };
1317
+
1318
+ const colorize = async function() {
1319
+ const response = await messaging.send('loggerUI', {
1320
+ what: 'getURLFilteringData',
1321
+ context: selectValue('select.dynamic.origin'),
1322
+ urls: targetURLs,
1323
+ type: uglyTypeFromSelector('dynamic'),
1324
+ });
1325
+ onColorsReady(response);
1326
+ };
1327
+
1328
+ const parseStaticInputs = function() {
1329
+ const options = [];
1330
+ const block = selectValue('select.static.action') === '';
1331
+ let filter = '';
1332
+ if ( !block ) {
1333
+ filter = '@@';
1334
+ }
1335
+ let value = selectValue('select.static.url');
1336
+ if ( value !== '' ) {
1337
+ if ( reSchemeOnly.test(value) ) {
1338
+ value = `|${value}`;
1339
+ } else {
1340
+ if ( value.endsWith('/') ) {
1341
+ value += '*';
1342
+ } else if ( /[/?]/.test(value) === false ) {
1343
+ value += '^';
1344
+ }
1345
+ value = `||${value}`;
1346
+ }
1347
+ }
1348
+ filter += value;
1349
+ value = selectValue('select.static.type');
1350
+ if ( value !== '' ) {
1351
+ options.push(uglyTypeFromSelector('static'));
1352
+ }
1353
+ value = selectValue('select.static.origin');
1354
+ if ( value !== '' ) {
1355
+ if ( value === targetDomain ) {
1356
+ options.push('1p');
1357
+ } else {
1358
+ options.push('domain=' + value);
1359
+ }
1360
+ }
1361
+ if ( block && selectValue('select.static.importance') !== '' ) {
1362
+ options.push('important');
1363
+ }
1364
+ if ( options.length ) {
1365
+ filter += '$' + options.join(',');
1366
+ }
1367
+ staticFilterNode().value = filter;
1368
+ updateWidgets();
1369
+ };
1370
+
1371
+ const updateWidgets = function() {
1372
+ const value = staticFilterNode().value;
1373
+ dom.cl.toggle(
1374
+ qs$(dialog, '#createStaticFilter'),
1375
+ 'disabled',
1376
+ createdStaticFilters.hasOwnProperty(value) || value === ''
1377
+ );
1378
+ };
1379
+
1380
+ const onClick = async function(ev) {
1381
+ const target = ev.target;
1382
+ const tcl = target.classList;
1383
+
1384
+ // Close entry tools
1385
+ if ( tcl.contains('closeButton') ) {
1386
+ ev.stopPropagation();
1387
+ toggleOff();
1388
+ return;
1389
+ }
1390
+
1391
+ // Select a pane
1392
+ if ( tcl.contains('header') ) {
1393
+ ev.stopPropagation();
1394
+ dom.attr(dialog, 'data-pane', dom.attr(target, 'data-pane'));
1395
+ return;
1396
+ }
1397
+
1398
+ // Toggle temporary exception filter
1399
+ if ( tcl.contains('exceptor') ) {
1400
+ ev.stopPropagation();
1401
+ const filter = filterFromTargetRow();
1402
+ const status = await messaging.send('loggerUI', {
1403
+ what: 'toggleInMemoryFilter',
1404
+ filter: toExceptionFilter(filter, dom.cl.has(targetRow, 'extendedRealm')),
1405
+ });
1406
+ const row = target.closest('div');
1407
+ dom.cl.toggle(row, 'exceptored', status);
1408
+ return;
1409
+ }
1410
+
1411
+ // Create static filter
1412
+ if ( target.id === 'createStaticFilter' ) {
1413
+ ev.stopPropagation();
1414
+ const value = staticFilterNode().value;
1415
+ // Avoid duplicates
1416
+ if ( createdStaticFilters.hasOwnProperty(value) ) { return; }
1417
+ createdStaticFilters[value] = true;
1418
+ // https://github.com/uBlockOrigin/uBlock-issues/issues/1281#issuecomment-704217175
1419
+ // TODO:
1420
+ // Figure a way to use the actual document URL. Currently using
1421
+ // a synthetic URL derived from the document hostname.
1422
+ if ( value !== '' ) {
1423
+ messaging.send('loggerUI', {
1424
+ what: 'createUserFilter',
1425
+ autoComment: true,
1426
+ filters: value,
1427
+ docURL: `https://${targetFrameHostname}/`,
1428
+ });
1429
+ }
1430
+ updateWidgets();
1431
+ return;
1432
+ }
1433
+
1434
+ // Save url filtering rule(s)
1435
+ if ( target.id === 'saveRules' ) {
1436
+ ev.stopPropagation();
1437
+ await messaging.send('loggerUI', {
1438
+ what: 'saveURLFilteringRules',
1439
+ context: selectValue('select.dynamic.origin'),
1440
+ urls: targetURLs,
1441
+ type: uglyTypeFromSelector('dynamic'),
1442
+ });
1443
+ colorize();
1444
+ return;
1445
+ }
1446
+
1447
+ const persist = !!ev.ctrlKey || !!ev.metaKey;
1448
+
1449
+ // Remove url filtering rule
1450
+ if ( tcl.contains('action') ) {
1451
+ ev.stopPropagation();
1452
+ await messaging.send('loggerUI', {
1453
+ what: 'setURLFilteringRule',
1454
+ context: selectValue('select.dynamic.origin'),
1455
+ url: dom.attr(target, 'data-url'),
1456
+ type: uglyTypeFromSelector('dynamic'),
1457
+ action: 0,
1458
+ persist: persist,
1459
+ });
1460
+ colorize();
1461
+ return;
1462
+ }
1463
+
1464
+ // add "allow" url filtering rule
1465
+ if ( tcl.contains('allow') ) {
1466
+ ev.stopPropagation();
1467
+ await messaging.send('loggerUI', {
1468
+ what: 'setURLFilteringRule',
1469
+ context: selectValue('select.dynamic.origin'),
1470
+ url: dom.attr(target.parentNode, 'data-url'),
1471
+ type: uglyTypeFromSelector('dynamic'),
1472
+ action: 2,
1473
+ persist: persist,
1474
+ });
1475
+ colorize();
1476
+ return;
1477
+ }
1478
+
1479
+ // add "block" url filtering rule
1480
+ if ( tcl.contains('noop') ) {
1481
+ ev.stopPropagation();
1482
+ await messaging.send('loggerUI', {
1483
+ what: 'setURLFilteringRule',
1484
+ context: selectValue('select.dynamic.origin'),
1485
+ url: dom.attr(target.parentNode, 'data-url'),
1486
+ type: uglyTypeFromSelector('dynamic'),
1487
+ action: 3,
1488
+ persist: persist,
1489
+ });
1490
+ colorize();
1491
+ return;
1492
+ }
1493
+
1494
+ // add "block" url filtering rule
1495
+ if ( tcl.contains('block') ) {
1496
+ ev.stopPropagation();
1497
+ await messaging.send('loggerUI', {
1498
+ what: 'setURLFilteringRule',
1499
+ context: selectValue('select.dynamic.origin'),
1500
+ url: dom.attr(target.parentNode, 'data-url'),
1501
+ type: uglyTypeFromSelector('dynamic'),
1502
+ action: 1,
1503
+ persist: persist,
1504
+ });
1505
+ colorize();
1506
+ return;
1507
+ }
1508
+
1509
+ // Highlight corresponding element in target web page
1510
+ if ( tcl.contains('picker') ) {
1511
+ ev.stopPropagation();
1512
+ messaging.send('loggerUI', {
1513
+ what: 'launchElementPicker',
1514
+ tabId: targetTabId,
1515
+ targetURL: 'img\t' + targetURLs[0],
1516
+ select: true,
1517
+ });
1518
+ return;
1519
+ }
1520
+
1521
+ // Reload tab associated with event
1522
+ if ( tcl.contains('reload') ) {
1523
+ ev.stopPropagation();
1524
+ messaging.send('loggerUI', {
1525
+ what: 'reloadTab',
1526
+ tabId: targetTabId,
1527
+ bypassCache: ev.ctrlKey || ev.metaKey || ev.shiftKey,
1528
+ });
1529
+ return;
1530
+ }
1531
+ };
1532
+
1533
+ const onSelectChange = function(ev) {
1534
+ const tcl = ev.target.classList;
1535
+
1536
+ if ( tcl.contains('dynamic') ) {
1537
+ colorize();
1538
+ return;
1539
+ }
1540
+
1541
+ if ( tcl.contains('static') ) {
1542
+ parseStaticInputs();
1543
+ return;
1544
+ }
1545
+ };
1546
+
1547
+ const onInputChange = function() {
1548
+ updateWidgets();
1549
+ };
1550
+
1551
+ const createPreview = function(type, url) {
1552
+ const cantPreview =
1553
+ type !== 'image' ||
1554
+ dom.cl.has(targetRow, 'networkRealm') === false ||
1555
+ dom.attr(targetRow, 'data-status') === '1';
1556
+
1557
+ // Whether picker can be used
1558
+ dom.cl.toggle(
1559
+ qs$(dialog, '.picker'),
1560
+ 'hide',
1561
+ targetTabId < 0 || cantPreview
1562
+ );
1563
+
1564
+ // Whether the resource can be previewed
1565
+ if ( cantPreview ) { return; }
1566
+
1567
+ const container = qs$(dialog, '.preview');
1568
+ dom.on(qs$(container, 'span'), 'click', ( ) => {
1569
+ const preview = dom.create('img');
1570
+ dom.attr(preview, 'src', url);
1571
+ container.replaceChild(preview, container.firstElementChild);
1572
+ }, { once: true });
1573
+
1574
+ dom.cl.remove(container, 'hide');
1575
+ };
1576
+
1577
+ // https://github.com/gorhill/uBlock/issues/1511
1578
+ const shortenLongString = function(url, max) {
1579
+ const urlLen = url.length;
1580
+ if ( urlLen <= max ) {
1581
+ return url;
1582
+ }
1583
+ const n = urlLen - max - 1;
1584
+ const i = (urlLen - n) / 2 | 0;
1585
+ return url.slice(0, i) + '…' + url.slice(i + n);
1586
+ };
1587
+
1588
+ // Build list of candidate URLs
1589
+ const createTargetURLs = function(url) {
1590
+ const matches = reRFC3986.exec(url);
1591
+ if ( matches === null ) { return []; }
1592
+ if ( typeof matches[2] !== 'string' || matches[2].length === 0 ) {
1593
+ return [ matches[1] ];
1594
+ }
1595
+ // Shortest URL for a valid URL filtering rule
1596
+ const urls = [];
1597
+ const rootURL = matches[1] + matches[2];
1598
+ urls.unshift(rootURL);
1599
+ const path = matches[3] || '';
1600
+ let pos = path.charAt(0) === '/' ? 1 : 0;
1601
+ while ( pos < path.length ) {
1602
+ pos = path.indexOf('/', pos);
1603
+ if ( pos === -1 ) {
1604
+ pos = path.length;
1605
+ } else {
1606
+ pos += 1;
1607
+ }
1608
+ urls.unshift(rootURL + path.slice(0, pos));
1609
+ }
1610
+ const query = matches[4] || '';
1611
+ if ( query !== '' ) {
1612
+ urls.unshift(rootURL + path + query);
1613
+ }
1614
+ return urls;
1615
+ };
1616
+
1617
+ const filterFromTargetRow = function() {
1618
+ return dom.text(targetRow.children[COLUMN_FILTER]);
1619
+ };
1620
+
1621
+ const aliasURLFromID = function(id) {
1622
+ if ( id === '' ) { return ''; }
1623
+ for ( const entry of loggerEntries ) {
1624
+ if ( entry.id !== id || entry.aliased ) { continue; }
1625
+ const fields = entry.textContent.split('\t');
1626
+ return fields[COLUMN_URL] || '';
1627
+ }
1628
+ return '';
1629
+ };
1630
+
1631
+ const toSummaryPaneFilterNode = async function(receiver, filter) {
1632
+ receiver.children[COLUMN_FILTER].textContent = filter;
1633
+ if ( dom.cl.has(targetRow, 'canLookup') === false ) { return; }
1634
+ const isException = reIsExceptionFilter.test(filter);
1635
+ let isExcepted = false;
1636
+ if ( isException ) {
1637
+ isExcepted = await messaging.send('loggerUI', {
1638
+ what: 'hasInMemoryFilter',
1639
+ filter: toExceptionFilter(filter, dom.cl.has(targetRow, 'extendedRealm')),
1640
+ });
1641
+ }
1642
+ if ( isException && isExcepted === false ) { return; }
1643
+ dom.cl.toggle(receiver, 'exceptored', isExcepted);
1644
+ receiver.children[2].style.visibility = '';
1645
+ };
1646
+
1647
+ const fillSummaryPaneFilterList = async function(rows) {
1648
+ const rawFilter = targetRow.children[COLUMN_FILTER].textContent;
1649
+
1650
+ const nodeFromFilter = function(filter, lists) {
1651
+ const fragment = document.createDocumentFragment();
1652
+ const template = qs$('#filterFinderListEntry > span');
1653
+ for ( const list of lists ) {
1654
+ const span = dom.clone(template);
1655
+ let a = qs$(span, 'a:nth-of-type(1)');
1656
+ a.href += encodeURIComponent(list.assetKey);
1657
+ a.append(i18n.patchUnicodeFlags(list.title));
1658
+ a = qs$(span, 'a:nth-of-type(2)');
1659
+ if ( list.supportURL ) {
1660
+ dom.attr(a, 'href', list.supportURL);
1661
+ } else {
1662
+ a.style.display = 'none';
1663
+ }
1664
+ if ( fragment.childElementCount !== 0 ) {
1665
+ fragment.appendChild(document.createTextNode('\n'));
1666
+ }
1667
+ fragment.appendChild(span);
1668
+ }
1669
+ return fragment;
1670
+ };
1671
+
1672
+ const handleResponse = function(response) {
1673
+ if ( response instanceof Object === false ) {
1674
+ response = {};
1675
+ }
1676
+ let bestMatchFilter = '';
1677
+ for ( const filter in response ) {
1678
+ if ( filter.length > bestMatchFilter.length ) {
1679
+ bestMatchFilter = filter;
1680
+ }
1681
+ }
1682
+ if (
1683
+ bestMatchFilter !== '' &&
1684
+ Array.isArray(response[bestMatchFilter])
1685
+ ) {
1686
+ toSummaryPaneFilterNode(rows[0], bestMatchFilter);
1687
+ rows[1].children[1].appendChild(nodeFromFilter(
1688
+ bestMatchFilter,
1689
+ response[bestMatchFilter]
1690
+ ));
1691
+ }
1692
+ // https://github.com/gorhill/uBlock/issues/2179
1693
+ if ( rows[1].children[1].childElementCount === 0 ) {
1694
+ i18n.safeTemplateToDOM(
1695
+ 'loggerStaticFilteringFinderSentence2',
1696
+ { filter: rawFilter },
1697
+ rows[1].children[1]
1698
+ );
1699
+ }
1700
+ };
1701
+
1702
+ if ( dom.cl.has(targetRow, 'networkRealm') ) {
1703
+ const response = await messaging.send('loggerUI', {
1704
+ what: 'listsFromNetFilter',
1705
+ rawFilter: rawFilter,
1706
+ });
1707
+ handleResponse(response);
1708
+ } else if ( dom.cl.has(targetRow, 'extendedRealm') ) {
1709
+ const response = await messaging.send('loggerUI', {
1710
+ what: 'listsFromCosmeticFilter',
1711
+ url: targetRow.children[COLUMN_URL].textContent,
1712
+ rawFilter: rawFilter,
1713
+ });
1714
+ handleResponse(response);
1715
+ }
1716
+ };
1717
+
1718
+ const fillSummaryPane = function() {
1719
+ const rows = qsa$(dialog, '.pane.details > div');
1720
+ const tr = targetRow;
1721
+ const trcl = tr.classList;
1722
+ const trch = tr.children;
1723
+ let text;
1724
+ // Filter and context
1725
+ text = filterFromTargetRow();
1726
+ if (
1727
+ (text !== '') &&
1728
+ (trcl.contains('extendedRealm') || trcl.contains('networkRealm'))
1729
+ ) {
1730
+ toSummaryPaneFilterNode(rows[0], text);
1731
+ } else {
1732
+ rows[0].style.display = 'none';
1733
+ }
1734
+ // Rule
1735
+ if (
1736
+ (text !== '') &&
1737
+ (
1738
+ trcl.contains('dynamicHost') ||
1739
+ trcl.contains('dynamicUrl') ||
1740
+ trcl.contains('switchRealm')
1741
+ )
1742
+ ) {
1743
+ rows[2].children[1].textContent = text;
1744
+ } else {
1745
+ rows[2].style.display = 'none';
1746
+ }
1747
+ // Filter list
1748
+ if ( trcl.contains('canLookup') ) {
1749
+ fillSummaryPaneFilterList(rows);
1750
+ } else {
1751
+ rows[1].style.display = 'none';
1752
+ }
1753
+ // Root and immediate contexts
1754
+ const tabhn = dom.attr(tr, 'data-tabhn') || '';
1755
+ const dochn = dom.attr(tr, 'data-dochn') || '';
1756
+ if ( tabhn !== '' && tabhn !== dochn ) {
1757
+ rows[3].children[1].textContent = tabhn;
1758
+ } else {
1759
+ rows[3].style.display = 'none';
1760
+ }
1761
+ if ( dochn !== '' ) {
1762
+ rows[4].children[1].textContent = dochn;
1763
+ } else {
1764
+ rows[4].style.display = 'none';
1765
+ }
1766
+ // Partyness
1767
+ text = dom.attr(tr, 'data-parties') || '';
1768
+ if ( text !== '' ) {
1769
+ rows[5].children[1].textContent = `(${trch[COLUMN_PARTYNESS].textContent})\u2002${text}`;
1770
+ } else {
1771
+ rows[5].style.display = 'none';
1772
+ }
1773
+ // Type
1774
+ text = trch[COLUMN_TYPE].textContent;
1775
+ if ( text !== '' ) {
1776
+ rows[6].children[1].textContent = text;
1777
+ } else {
1778
+ rows[6].style.display = 'none';
1779
+ }
1780
+ // URL
1781
+ const canonicalURL = trch[COLUMN_URL].textContent;
1782
+ if ( canonicalURL !== '' ) {
1783
+ const attr = dom.attr(tr, 'data-status') || '';
1784
+ if ( attr !== '' ) {
1785
+ dom.attr(rows[7], 'data-status', attr);
1786
+ if ( tr.hasAttribute('data-modifier') ) {
1787
+ dom.attr(rows[7], 'data-modifier', '');
1788
+ }
1789
+ }
1790
+ rows[7].children[1].appendChild(dom.clone(trch[COLUMN_URL]));
1791
+ } else {
1792
+ rows[7].style.display = 'none';
1793
+ }
1794
+ // Alias URL
1795
+ text = dom.attr(tr, 'data-aliasid');
1796
+ const aliasURL = text ? aliasURLFromID(text) : '';
1797
+ if ( aliasURL !== '' ) {
1798
+ rows[8].children[1].textContent =
1799
+ hostnameFromURI(aliasURL) + ' \u21d2\n\u2003' +
1800
+ hostnameFromURI(canonicalURL);
1801
+ rows[9].children[1].textContent = aliasURL;
1802
+ } else {
1803
+ rows[8].style.display = 'none';
1804
+ rows[9].style.display = 'none';
1805
+ }
1806
+ };
1807
+
1808
+ // Fill dynamic URL filtering pane
1809
+ const fillDynamicPane = function() {
1810
+ if ( dom.cl.has(targetRow, 'extendedRealm') ) { return; }
1811
+
1812
+ // https://github.com/uBlockOrigin/uBlock-issues/issues/662#issuecomment-509220702
1813
+ if ( targetType === 'doc' ) { return; }
1814
+
1815
+ // https://github.com/gorhill/uBlock/issues/2469
1816
+ if ( targetURLs.length === 0 || reSchemeOnly.test(targetURLs[0]) ) {
1817
+ return;
1818
+ }
1819
+
1820
+ // Fill context selector
1821
+ let select = selectNode('select.dynamic.origin');
1822
+ fillOriginSelect(select, targetPageHostname, targetPageDomain);
1823
+ const option = document.createElement('option');
1824
+ option.textContent = '*';
1825
+ dom.attr(option, 'value', '*');
1826
+ select.appendChild(option);
1827
+
1828
+ // Fill type selector
1829
+ select = selectNode('select.dynamic.type');
1830
+ select.options[0].textContent = targetType;
1831
+ dom.attr(select.options[0], 'value', targetType);
1832
+ select.selectedIndex = 0;
1833
+
1834
+ // Fill entries
1835
+ const menuEntryTemplate = qs$(dialog, '.dynamic .toolbar .entry');
1836
+ const tbody = qs$(dialog, '.dynamic .entries');
1837
+ for ( const targetURL of targetURLs ) {
1838
+ const menuEntry = dom.clone(menuEntryTemplate);
1839
+ dom.attr(menuEntry.children[0], 'data-url', targetURL);
1840
+ menuEntry.children[1].textContent = shortenLongString(targetURL, 128);
1841
+ tbody.appendChild(menuEntry);
1842
+ }
1843
+
1844
+ colorize();
1845
+ };
1846
+
1847
+ const fillOriginSelect = function(select, hostname, domain) {
1848
+ const template = i18n$('loggerStaticFilteringSentencePartOrigin');
1849
+ let value = hostname;
1850
+ for (;;) {
1851
+ const option = document.createElement('option');
1852
+ dom.attr(option, 'value', value);
1853
+ option.textContent = template.replace('{{origin}}', value);
1854
+ select.appendChild(option);
1855
+ if ( value === domain ) { break; }
1856
+ const pos = value.indexOf('.');
1857
+ if ( pos === -1 ) { break; }
1858
+ value = value.slice(pos + 1);
1859
+ }
1860
+ };
1861
+
1862
+ // Fill static filtering pane
1863
+ const fillStaticPane = function() {
1864
+ if ( dom.cl.has(targetRow, 'extendedRealm') ) { return; }
1865
+
1866
+ const template = i18n$('loggerStaticFilteringSentence');
1867
+ const rePlaceholder = /\{\{[^}]+?\}\}/g;
1868
+ const nodes = [];
1869
+ let pos = 0;
1870
+ for (;;) {
1871
+ const match = rePlaceholder.exec(template);
1872
+ if ( match === null ) { break; }
1873
+ if ( pos !== match.index ) {
1874
+ nodes.push(document.createTextNode(template.slice(pos, match.index)));
1875
+ }
1876
+ pos = rePlaceholder.lastIndex;
1877
+ let select, option;
1878
+ switch ( match[0] ) {
1879
+ case '{{br}}':
1880
+ nodes.push(document.createElement('br'));
1881
+ break;
1882
+
1883
+ case '{{action}}':
1884
+ select = document.createElement('select');
1885
+ select.className = 'static action';
1886
+ option = document.createElement('option');
1887
+ dom.attr(option, 'value', '');
1888
+ option.textContent = i18n$('loggerStaticFilteringSentencePartBlock');
1889
+ select.appendChild(option);
1890
+ option = document.createElement('option');
1891
+ dom.attr(option, 'value', '@@');
1892
+ option.textContent = i18n$('loggerStaticFilteringSentencePartAllow');
1893
+ select.appendChild(option);
1894
+ nodes.push(select);
1895
+ break;
1896
+
1897
+ case '{{type}}': {
1898
+ const filterType = staticFilterTypes[targetType] || targetType;
1899
+ select = document.createElement('select');
1900
+ select.className = 'static type';
1901
+ option = document.createElement('option');
1902
+ dom.attr(option, 'value', filterType);
1903
+ option.textContent = i18n$('loggerStaticFilteringSentencePartType').replace('{{type}}', filterType);
1904
+ select.appendChild(option);
1905
+ option = document.createElement('option');
1906
+ dom.attr(option, 'value', '');
1907
+ option.textContent = i18n$('loggerStaticFilteringSentencePartAnyType');
1908
+ select.appendChild(option);
1909
+ nodes.push(select);
1910
+ break;
1911
+ }
1912
+ case '{{url}}':
1913
+ select = document.createElement('select');
1914
+ select.className = 'static url';
1915
+ for ( const targetURL of targetURLs ) {
1916
+ const value = targetURL.replace(/^[a-z-]+:\/\//, '');
1917
+ option = document.createElement('option');
1918
+ dom.attr(option, 'value', value);
1919
+ option.textContent = shortenLongString(value, 128);
1920
+ select.appendChild(option);
1921
+ }
1922
+ nodes.push(select);
1923
+ break;
1924
+
1925
+ case '{{origin}}':
1926
+ select = document.createElement('select');
1927
+ select.className = 'static origin';
1928
+ fillOriginSelect(select, targetFrameHostname, targetFrameDomain);
1929
+ option = document.createElement('option');
1930
+ dom.attr(option, 'value', '');
1931
+ option.textContent = i18n$('loggerStaticFilteringSentencePartAnyOrigin');
1932
+ select.appendChild(option);
1933
+ nodes.push(select);
1934
+ break;
1935
+
1936
+ case '{{importance}}':
1937
+ select = document.createElement('select');
1938
+ select.className = 'static importance';
1939
+ option = document.createElement('option');
1940
+ dom.attr(option, 'value', '');
1941
+ option.textContent = i18n$('loggerStaticFilteringSentencePartNotImportant');
1942
+ select.appendChild(option);
1943
+ option = document.createElement('option');
1944
+ dom.attr(option, 'value', 'important');
1945
+ option.textContent = i18n$('loggerStaticFilteringSentencePartImportant');
1946
+ select.appendChild(option);
1947
+ nodes.push(select);
1948
+ break;
1949
+
1950
+ default:
1951
+ break;
1952
+ }
1953
+ }
1954
+ if ( pos < template.length ) {
1955
+ nodes.push(document.createTextNode(template.slice(pos)));
1956
+ }
1957
+ const parent = qs$(dialog, 'div.panes > .static > div:first-of-type');
1958
+ for ( let i = 0; i < nodes.length; i++ ) {
1959
+ parent.appendChild(nodes[i]);
1960
+ }
1961
+ parseStaticInputs();
1962
+ };
1963
+
1964
+ const moveDialog = ev => {
1965
+ if ( ev.button !== 0 && ev.touches === undefined ) { return; }
1966
+ const widget = qs$('#netInspector .entryTools');
1967
+ onStartMovingWidget(ev, widget, ( ) => {
1968
+ vAPI.localStorage.setItem(
1969
+ 'loggerUI.entryTools',
1970
+ JSON.stringify({
1971
+ bottom: widget.style.bottom,
1972
+ left: widget.style.left,
1973
+ right: widget.style.right,
1974
+ top: widget.style.top,
1975
+ })
1976
+ );
1977
+ });
1978
+ };
1979
+
1980
+ const fillDialog = function(domains) {
1981
+ dialog = dom.clone('#templates .netFilteringDialog');
1982
+ dom.cl.toggle(
1983
+ dialog,
1984
+ 'extendedRealm',
1985
+ dom.cl.has(targetRow, 'extendedRealm')
1986
+ );
1987
+ targetDomain = domains[0];
1988
+ targetPageDomain = domains[1];
1989
+ targetFrameDomain = domains[2];
1990
+ createPreview(targetType, targetURLs[0]);
1991
+ fillSummaryPane();
1992
+ fillDynamicPane();
1993
+ fillStaticPane();
1994
+ dom.on(dialog, 'click', ev => { onClick(ev); }, true);
1995
+ dom.on(dialog, 'change', onSelectChange, true);
1996
+ dom.on(dialog, 'input', onInputChange, true);
1997
+ const container = qs$('#netInspector .entryTools');
1998
+ if ( container.firstChild ) {
1999
+ container.replaceChild(dialog, container.firstChild);
2000
+ } else {
2001
+ container.append(dialog);
2002
+ }
2003
+ const moveBand = qs$(dialog, '.moveBand');
2004
+ dom.on(moveBand, 'mousedown', moveDialog);
2005
+ dom.on(moveBand, 'touchstart', moveDialog);
2006
+ };
2007
+
2008
+ const toggleOn = async function(ev) {
2009
+ targetRow = ev.target.closest('.canDetails');
2010
+ if ( targetRow === null ) { return; }
2011
+ ev.stopPropagation();
2012
+ targetTabId = tabIdFromAttribute(targetRow);
2013
+ targetType = targetRow.children[COLUMN_TYPE].textContent.trim() || '';
2014
+ targetURLs = createTargetURLs(targetRow.children[COLUMN_URL].textContent);
2015
+ targetPageHostname = dom.attr(targetRow, 'data-tabhn') || '';
2016
+ targetFrameHostname = dom.attr(targetRow, 'data-dochn') || '';
2017
+
2018
+ // We need the root domain names for best user experience.
2019
+ const domains = await messaging.send('loggerUI', {
2020
+ what: 'getDomainNames',
2021
+ targets: [
2022
+ targetURLs[0],
2023
+ targetPageHostname,
2024
+ targetFrameHostname
2025
+ ],
2026
+ });
2027
+ fillDialog(domains);
2028
+ };
2029
+
2030
+ const toggleOff = function() {
2031
+ const container = qs$('#netInspector .entryTools');
2032
+ if ( container.firstChild ) {
2033
+ container.firstChild.remove();
2034
+ }
2035
+ targetURLs = [];
2036
+ targetRow = null;
2037
+ dialog = null;
2038
+ };
2039
+
2040
+ // Restore position of entry tools dialog
2041
+ vAPI.localStorage.getItemAsync(
2042
+ 'loggerUI.entryTools',
2043
+ ).then(response => {
2044
+ if ( typeof response !== 'string' ) { return; }
2045
+ const settings = JSON.parse(response);
2046
+ const widget = qs$('#netInspector .entryTools');
2047
+ widget.style.bottom = '';
2048
+ widget.style.left = settings.left || '';
2049
+ widget.style.right = settings.right || '';
2050
+ widget.style.top = settings.top || '';
2051
+ if ( /^-/.test(widget.style.top) ) {
2052
+ widget.style.top = '0';
2053
+ }
2054
+ });
2055
+
2056
+ dom.on(
2057
+ '#netInspector',
2058
+ 'click',
2059
+ '.canDetails > span:not(:nth-of-type(4)):not(:nth-of-type(8))',
2060
+ ev => { toggleOn(ev); }
2061
+ );
2062
+
2063
+ dom.on(
2064
+ '#netInspector',
2065
+ 'click',
2066
+ '.logEntry > div > span:nth-of-type(8) a',
2067
+ ev => {
2068
+ vAPI.messaging.send('codeViewer', {
2069
+ what: 'gotoURL',
2070
+ details: {
2071
+ url: ev.target.getAttribute('href'),
2072
+ select: true,
2073
+ },
2074
+ });
2075
+ ev.preventDefault();
2076
+ ev.stopPropagation();
2077
+ }
2078
+ );
2079
+ })();
2080
+
2081
+ /******************************************************************************/
2082
+ /******************************************************************************/
2083
+
2084
+ const rowFilterer = (( ) => {
2085
+ const userFilters = [];
2086
+ const builtinFilters = [];
2087
+
2088
+ let masterFilterSwitch = true;
2089
+ let filters = [];
2090
+
2091
+ const parseInput = function() {
2092
+ userFilters.length = 0;
2093
+
2094
+ const rawParts = qs$('#filterInput > input').value.trim().split(/\s+/);
2095
+ const n = rawParts.length;
2096
+ const reStrs = [];
2097
+ let not = false;
2098
+ for ( let i = 0; i < n; i++ ) {
2099
+ let rawPart = rawParts[i];
2100
+ if ( rawPart.charAt(0) === '!' ) {
2101
+ if ( reStrs.length === 0 ) {
2102
+ not = true;
2103
+ }
2104
+ rawPart = rawPart.slice(1);
2105
+ }
2106
+ let reStr = '';
2107
+ if ( rawPart.startsWith('/') && rawPart.endsWith('/') ) {
2108
+ reStr = rawPart.slice(1, -1);
2109
+ try {
2110
+ new RegExp(reStr);
2111
+ } catch(ex) {
2112
+ reStr = '';
2113
+ }
2114
+ }
2115
+ if ( reStr === '' ) {
2116
+ const hardBeg = rawPart.startsWith('|');
2117
+ if ( hardBeg ) {
2118
+ rawPart = rawPart.slice(1);
2119
+ }
2120
+ const hardEnd = rawPart.endsWith('|');
2121
+ if ( hardEnd ) {
2122
+ rawPart = rawPart.slice(0, -1);
2123
+ }
2124
+ // https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions
2125
+ reStr = rawPart.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2126
+ // https://github.com/orgs/uBlockOrigin/teams/ublock-issues-volunteers/discussions/51
2127
+ // Be more flexible when interpreting leading/trailing pipes,
2128
+ // as leading/trailing pipes are often used in static filters.
2129
+ if ( hardBeg ) {
2130
+ reStr = reStr !== '' ? '(?:^|\\s|\\|)' + reStr : '\\|';
2131
+ }
2132
+ if ( hardEnd ) {
2133
+ reStr += '(?:\\||\\s|$)';
2134
+ }
2135
+ }
2136
+ if ( reStr === '' ) { continue; }
2137
+ reStrs.push(reStr);
2138
+ if ( i < (n - 1) && rawParts[i + 1] === '||' ) {
2139
+ i += 1;
2140
+ continue;
2141
+ }
2142
+ reStr = reStrs.length === 1 ? reStrs[0] : reStrs.join('|');
2143
+ userFilters.push({
2144
+ re: new RegExp(reStr, 'i'),
2145
+ r: !not
2146
+ });
2147
+ reStrs.length = 0;
2148
+ not = false;
2149
+ }
2150
+ filters = builtinFilters.concat(userFilters);
2151
+ };
2152
+
2153
+ const filterOne = function(logEntry) {
2154
+ if (
2155
+ logEntry.dead ||
2156
+ selectedTabId !== 0 &&
2157
+ (
2158
+ logEntry.tabId === undefined ||
2159
+ logEntry.tabId > 0 && logEntry.tabId !== selectedTabId
2160
+ )
2161
+ ) {
2162
+ return false;
2163
+ }
2164
+
2165
+ if ( masterFilterSwitch === false || filters.length === 0 ) {
2166
+ return true;
2167
+ }
2168
+
2169
+ // Do not filter out tab load event, they help separate key sections
2170
+ // of logger.
2171
+ if ( logEntry.type === 'tabLoad' ) { return true; }
2172
+
2173
+ for ( const f of filters ) {
2174
+ if ( f.re.test(logEntry.textContent) !== f.r ) { return false; }
2175
+ }
2176
+ return true;
2177
+ };
2178
+
2179
+ const filterAll = function() {
2180
+ filteredLoggerEntries = [];
2181
+ filteredLoggerEntryVoidedCount = 0;
2182
+ for ( const entry of loggerEntries ) {
2183
+ if ( filterOne(entry) === false ) { continue; }
2184
+ filteredLoggerEntries.push(entry);
2185
+ if ( entry.voided ) {
2186
+ filteredLoggerEntryVoidedCount += 1;
2187
+ }
2188
+ }
2189
+ viewPort.updateContent(0);
2190
+ dom.cl.toggle('#filterButton', 'active', filters.length !== 0);
2191
+ dom.cl.toggle('#clean', 'disabled', filteredLoggerEntryVoidedCount === 0);
2192
+ dom.cl.toggle('#clear', 'disabled', filteredLoggerEntries.length === 0);
2193
+ };
2194
+
2195
+ const onFilterChangedAsync = (( ) => {
2196
+ const commit = ( ) => {
2197
+ parseInput();
2198
+ filterAll();
2199
+ };
2200
+ const timer = vAPI.defer.create(commit);
2201
+ return ( ) => {
2202
+ timer.offon(750);
2203
+ };
2204
+ })();
2205
+
2206
+ const onFilterButton = function() {
2207
+ masterFilterSwitch = !masterFilterSwitch;
2208
+ dom.cl.toggle('#netInspector', 'f', masterFilterSwitch);
2209
+ filterAll();
2210
+ };
2211
+
2212
+ const onToggleExtras = function(ev) {
2213
+ dom.cl.toggle(ev.target, 'expanded');
2214
+ };
2215
+
2216
+ const builtinFilterExpression = function() {
2217
+ builtinFilters.length = 0;
2218
+ const filtexElems = qsa$('#filterExprPicker [data-filtex]');
2219
+ const orExprs = [];
2220
+ let not = false;
2221
+ for ( const filtexElem of filtexElems ) {
2222
+ const filtex = filtexElem.dataset.filtex;
2223
+ const active = dom.cl.has(filtexElem, 'on');
2224
+ if ( filtex === '!' ) {
2225
+ if ( orExprs.length !== 0 ) {
2226
+ builtinFilters.push({
2227
+ re: new RegExp(orExprs.join('|')),
2228
+ r: !not
2229
+ });
2230
+ orExprs.length = 0;
2231
+ }
2232
+ not = active;
2233
+ } else if ( active ) {
2234
+ orExprs.push(filtex);
2235
+ }
2236
+ }
2237
+ if ( orExprs.length !== 0 ) {
2238
+ builtinFilters.push({
2239
+ re: new RegExp(orExprs.join('|')),
2240
+ r: !not
2241
+ });
2242
+ }
2243
+ filters = builtinFilters.concat(userFilters);
2244
+ dom.cl.toggle('#filterExprButton', 'active', builtinFilters.length !== 0);
2245
+ filterAll();
2246
+ };
2247
+
2248
+ dom.on('#filterButton', 'click', onFilterButton);
2249
+ dom.on('#filterInput > input', 'input', onFilterChangedAsync);
2250
+ dom.on('#filterExprButton', 'click', onToggleExtras);
2251
+ dom.on('#filterExprPicker', 'click', '[data-filtex]', ev => {
2252
+ dom.cl.toggle(ev.target, 'on');
2253
+ builtinFilterExpression();
2254
+ });
2255
+
2256
+ // https://github.com/gorhill/uBlock/issues/404
2257
+ // Ensure page state is in sync with the state of its various widgets.
2258
+ parseInput();
2259
+ builtinFilterExpression();
2260
+ filterAll();
2261
+
2262
+ return { filterOne, filterAll };
2263
+ })();
2264
+
2265
+ /******************************************************************************/
2266
+
2267
+ // Discard logger entries to prevent undue memory usage growth. The criteria
2268
+ // to discard are multiple and user configurable:
2269
+ //
2270
+ // - Max number of page load per distinct tab
2271
+ // - Max number of entry per distinct tab
2272
+ // - Max entry age
2273
+
2274
+ const rowJanitor = (( ) => {
2275
+ const tabIdToDiscard = new Set();
2276
+ const tabIdToLoadCountMap = new Map();
2277
+ const tabIdToEntryCountMap = new Map();
2278
+
2279
+ let rowIndex = 0;
2280
+
2281
+ const discard = function(deadline) {
2282
+ const opts = loggerSettings.discard;
2283
+ const maxLoadCount = typeof opts.maxLoadCount === 'number'
2284
+ ? opts.maxLoadCount
2285
+ : 0;
2286
+ const maxEntryCount = typeof opts.maxEntryCount === 'number'
2287
+ ? opts.maxEntryCount
2288
+ : 0;
2289
+ const obsolete = typeof opts.maxAge === 'number'
2290
+ ? Date.now() - opts.maxAge * 60000
2291
+ : 0;
2292
+
2293
+ let i = rowIndex;
2294
+ // TODO: below should not happen -- remove when confirmed.
2295
+ if ( i >= loggerEntries.length ) {
2296
+ i = 0;
2297
+ }
2298
+
2299
+ if ( i === 0 ) {
2300
+ tabIdToDiscard.clear();
2301
+ tabIdToLoadCountMap.clear();
2302
+ tabIdToEntryCountMap.clear();
2303
+ }
2304
+
2305
+ let idel = -1;
2306
+ let bufferedTabId = 0;
2307
+ let bufferedEntryCount = 0;
2308
+ let modified = false;
2309
+
2310
+ while ( i < loggerEntries.length ) {
2311
+
2312
+ if ( i % 64 === 0 && deadline.timeRemaining() === 0 ) { break; }
2313
+
2314
+ const entry = loggerEntries[i];
2315
+ const tabId = entry.tabId || 0;
2316
+
2317
+ if ( entry.dead || tabIdToDiscard.has(tabId) ) {
2318
+ if ( idel === -1 ) { idel = i; }
2319
+ i += 1;
2320
+ continue;
2321
+ }
2322
+
2323
+ if ( maxLoadCount !== 0 && entry.type === 'tabLoad' ) {
2324
+ let count = (tabIdToLoadCountMap.get(tabId) || 0) + 1;
2325
+ tabIdToLoadCountMap.set(tabId, count);
2326
+ if ( count >= maxLoadCount ) {
2327
+ tabIdToDiscard.add(tabId);
2328
+ }
2329
+ }
2330
+
2331
+ if ( maxEntryCount !== 0 ) {
2332
+ if ( bufferedTabId !== tabId ) {
2333
+ if ( bufferedEntryCount !== 0 ) {
2334
+ tabIdToEntryCountMap.set(bufferedTabId, bufferedEntryCount);
2335
+ }
2336
+ bufferedTabId = tabId;
2337
+ bufferedEntryCount = tabIdToEntryCountMap.get(tabId) || 0;
2338
+ }
2339
+ bufferedEntryCount += 1;
2340
+ if ( bufferedEntryCount >= maxEntryCount ) {
2341
+ tabIdToDiscard.add(bufferedTabId);
2342
+ }
2343
+ }
2344
+
2345
+ // Since entries in the logger are chronologically ordered,
2346
+ // everything below obsolete is to be discarded.
2347
+ if ( obsolete !== 0 && entry.tstamp <= obsolete ) {
2348
+ if ( idel === -1 ) { idel = i; }
2349
+ break;
2350
+ }
2351
+
2352
+ if ( idel !== -1 ) {
2353
+ loggerEntries.copyWithin(idel, i);
2354
+ loggerEntries.length -= i - idel;
2355
+ idel = -1;
2356
+ modified = true;
2357
+ }
2358
+
2359
+ i += 1;
2360
+ }
2361
+
2362
+ if ( idel !== -1 ) {
2363
+ loggerEntries.length = idel;
2364
+ modified = true;
2365
+ }
2366
+
2367
+ if ( i >= loggerEntries.length ) { i = 0; }
2368
+ rowIndex = i;
2369
+
2370
+ if ( rowIndex === 0 ) {
2371
+ tabIdToDiscard.clear();
2372
+ tabIdToLoadCountMap.clear();
2373
+ tabIdToEntryCountMap.clear();
2374
+ }
2375
+
2376
+ if ( modified === false ) { return; }
2377
+
2378
+ rowFilterer.filterAll();
2379
+ };
2380
+
2381
+ const discardAsync = function(deadline) {
2382
+ if ( deadline ) {
2383
+ discard(deadline);
2384
+ }
2385
+ janitorTimer.onidle(1889);
2386
+ };
2387
+
2388
+ const janitorTimer = vAPI.defer.create(discardAsync);
2389
+
2390
+ // Clear voided entries from the logger's visible content.
2391
+ //
2392
+ // Voided entries should be visible only from the "All" option of the
2393
+ // tab selector.
2394
+ //
2395
+ const clean = function() {
2396
+ if ( filteredLoggerEntries.length === 0 ) { return; }
2397
+
2398
+ let j = 0;
2399
+ let targetEntry = filteredLoggerEntries[0];
2400
+ for ( const entry of loggerEntries ) {
2401
+ if ( entry !== targetEntry ) { continue; }
2402
+ if ( entry.voided ) {
2403
+ entry.dead = true;
2404
+ }
2405
+ j += 1;
2406
+ if ( j === filteredLoggerEntries.length ) { break; }
2407
+ targetEntry = filteredLoggerEntries[j];
2408
+ }
2409
+ rowFilterer.filterAll();
2410
+ };
2411
+
2412
+ // Clear the logger's visible content.
2413
+ //
2414
+ // "Unrelated" entries -- shown for convenience -- will be also cleared
2415
+ // if and only if the filtered logger content is made entirely of unrelated
2416
+ // entries. In effect, this means clicking a second time on the eraser will
2417
+ // cause unrelated entries to also be cleared.
2418
+ //
2419
+ const clear = function() {
2420
+ if ( filteredLoggerEntries.length === 0 ) { return; }
2421
+
2422
+ let clearUnrelated = true;
2423
+ if ( selectedTabId !== 0 ) {
2424
+ for ( const entry of filteredLoggerEntries ) {
2425
+ if ( entry.tabId === selectedTabId ) {
2426
+ clearUnrelated = false;
2427
+ break;
2428
+ }
2429
+ }
2430
+ }
2431
+
2432
+ let j = 0;
2433
+ let targetEntry = filteredLoggerEntries[0];
2434
+ for ( const entry of loggerEntries ) {
2435
+ if ( entry !== targetEntry ) { continue; }
2436
+ if ( entry.tabId === selectedTabId || clearUnrelated ) {
2437
+ entry.dead = true;
2438
+ }
2439
+ j += 1;
2440
+ if ( j === filteredLoggerEntries.length ) { break; }
2441
+ targetEntry = filteredLoggerEntries[j];
2442
+ }
2443
+ rowFilterer.filterAll();
2444
+ };
2445
+
2446
+ discardAsync();
2447
+
2448
+ dom.on('#clean', 'click', clean);
2449
+ dom.on('#clear', 'click', clear);
2450
+
2451
+ return {
2452
+ inserted: function(count) {
2453
+ if ( rowIndex !== 0 ) {
2454
+ rowIndex += count;
2455
+ }
2456
+ },
2457
+ };
2458
+ })();
2459
+
2460
+ /******************************************************************************/
2461
+
2462
+ const pauseNetInspector = function() {
2463
+ netInspectorPaused = dom.cl.toggle('#netInspector', 'paused');
2464
+ };
2465
+
2466
+ /******************************************************************************/
2467
+
2468
+ const toggleVCompactView = function() {
2469
+ dom.cl.toggle('#netInspector .vCompactToggler', 'vExpanded');
2470
+ viewPort.updateLayout();
2471
+ };
2472
+
2473
+ /******************************************************************************/
2474
+
2475
+ const popupManager = (( ) => {
2476
+ let realTabId = 0;
2477
+ let popup = null;
2478
+ let popupObserver = null;
2479
+
2480
+ const resizePopup = function() {
2481
+ if ( popup === null ) { return; }
2482
+ const popupBody = popup.contentWindow.document.body;
2483
+ if ( popupBody.clientWidth !== 0 && popup.clientWidth !== popupBody.clientWidth ) {
2484
+ popup.style.setProperty('width', popupBody.clientWidth + 'px');
2485
+ }
2486
+ if ( popupBody.clientHeight !== 0 && popup.clientHeight !== popupBody.clientHeight ) {
2487
+ popup.style.setProperty('height', popupBody.clientHeight + 'px');
2488
+ }
2489
+ };
2490
+
2491
+ const onLoad = function() {
2492
+ resizePopup();
2493
+ popupObserver.observe(popup.contentDocument.body, {
2494
+ subtree: true,
2495
+ attributes: true
2496
+ });
2497
+ };
2498
+
2499
+ const setTabId = function(tabId) {
2500
+ if ( popup === null ) { return; }
2501
+ dom.attr(popup, 'src', `popup-fenix.html?portrait=1&tabId=${tabId}`);
2502
+ };
2503
+
2504
+ const onTabIdChanged = function() {
2505
+ const tabId = tabIdFromPageSelector();
2506
+ if ( tabId === 0 ) { return toggleOff(); }
2507
+ realTabId = tabId;
2508
+ setTabId(realTabId);
2509
+ };
2510
+
2511
+ const toggleOn = function() {
2512
+ const tabId = tabIdFromPageSelector();
2513
+ if ( tabId === 0 ) { return; }
2514
+ realTabId = tabId;
2515
+
2516
+ popup = qs$('#popupContainer');
2517
+
2518
+ dom.on(popup, 'load', onLoad);
2519
+ popupObserver = new MutationObserver(resizePopup);
2520
+
2521
+ const parent = qs$('#inspectors');
2522
+ const rect = parent.getBoundingClientRect();
2523
+ popup.style.setProperty('right', `${rect.right - parent.clientWidth}px`);
2524
+ dom.cl.add(parent, 'popupOn');
2525
+
2526
+ dom.on(document, 'tabIdChanged', onTabIdChanged);
2527
+
2528
+ setTabId(realTabId);
2529
+ dom.cl.add('#showpopup', 'active');
2530
+ };
2531
+
2532
+ const toggleOff = function() {
2533
+ dom.cl.remove('#showpopup', 'active');
2534
+ dom.off(document, 'tabIdChanged', onTabIdChanged);
2535
+ dom.cl.remove('#inspectors', 'popupOn');
2536
+ dom.off(popup, 'load', onLoad);
2537
+ popupObserver.disconnect();
2538
+ popupObserver = null;
2539
+ dom.attr(popup, 'src', '');
2540
+
2541
+ realTabId = 0;
2542
+ };
2543
+
2544
+ const api = {
2545
+ get tabId() { return realTabId || 0; },
2546
+ toggleOff: function() {
2547
+ if ( realTabId !== 0 ) {
2548
+ toggleOff();
2549
+ }
2550
+ }
2551
+ };
2552
+
2553
+ dom.on('#showpopup', 'click', ( ) => {
2554
+ void (realTabId === 0 ? toggleOn() : toggleOff());
2555
+ });
2556
+
2557
+ return api;
2558
+ })();
2559
+
2560
+ /******************************************************************************/
2561
+
2562
+ // Filter hit stats' MVP ("minimum viable product")
2563
+ //
2564
+ const loggerStats = (( ) => {
2565
+ const enabled = false;
2566
+ const filterHits = new Map();
2567
+ let dialog;
2568
+ let timer;
2569
+ const makeRow = function() {
2570
+ const div = document.createElement('div');
2571
+ div.appendChild(document.createElement('span'));
2572
+ div.appendChild(document.createElement('span'));
2573
+ return div;
2574
+ };
2575
+
2576
+ const fillRow = function(div, entry) {
2577
+ div.children[0].textContent = entry[1].toLocaleString();
2578
+ div.children[1].textContent = entry[0];
2579
+ };
2580
+
2581
+ const updateList = function() {
2582
+ const sortedHits = Array.from(filterHits).sort((a, b) => {
2583
+ return b[1] - a[1];
2584
+ });
2585
+
2586
+ const doc = document;
2587
+ const parent = qs$(dialog, '.sortedEntries');
2588
+ let i = 0;
2589
+
2590
+ // Reuse existing rows
2591
+ for ( let iRow = 0; iRow < parent.childElementCount; iRow++ ) {
2592
+ if ( i === sortedHits.length ) { break; }
2593
+ fillRow(parent.children[iRow], sortedHits[i]);
2594
+ i += 1;
2595
+ }
2596
+
2597
+ // Append new rows
2598
+ if ( i < sortedHits.length ) {
2599
+ const list = doc.createDocumentFragment();
2600
+ for ( ; i < sortedHits.length; i++ ) {
2601
+ const div = makeRow();
2602
+ fillRow(div, sortedHits[i]);
2603
+ list.appendChild(div);
2604
+ }
2605
+ parent.appendChild(list);
2606
+ }
2607
+
2608
+ // Remove extraneous rows
2609
+ // [Should never happen at this point in this current
2610
+ // bare-bone implementation]
2611
+ };
2612
+
2613
+ const toggleOn = function() {
2614
+ dialog = modalDialog.create(
2615
+ '#loggerStatsDialog',
2616
+ ( ) => {
2617
+ dialog = undefined;
2618
+ if ( timer !== undefined ) {
2619
+ self.cancelIdleCallback(timer);
2620
+ timer = undefined;
2621
+ }
2622
+ }
2623
+ );
2624
+ updateList();
2625
+ modalDialog.show();
2626
+ };
2627
+
2628
+ dom.on('#loggerStats', 'click', toggleOn);
2629
+
2630
+ return {
2631
+ processFilter: function(filter) {
2632
+ if ( enabled !== true ) { return; }
2633
+ if ( filter.source !== 'static' && filter.source !== 'cosmetic' ) {
2634
+ return;
2635
+ }
2636
+ filterHits.set(filter.raw, (filterHits.get(filter.raw) || 0) + 1);
2637
+ if ( dialog === undefined || timer !== undefined ) { return; }
2638
+ timer = self.requestIdleCallback(
2639
+ ( ) => {
2640
+ timer = undefined;
2641
+ updateList();
2642
+ },
2643
+ { timeout: 2001 }
2644
+ );
2645
+ }
2646
+ };
2647
+ })();
2648
+
2649
+ /******************************************************************************/
2650
+
2651
+ (( ) => {
2652
+ const lines = [];
2653
+ const options = {
2654
+ format: 'list',
2655
+ encoding: 'markdown',
2656
+ time: 'anonymous',
2657
+ };
2658
+ let dialog;
2659
+
2660
+ const collectLines = function() {
2661
+ lines.length = 0;
2662
+ let t0 = filteredLoggerEntries.length !== 0
2663
+ ? filteredLoggerEntries[filteredLoggerEntries.length - 1].tstamp
2664
+ : 0;
2665
+ for ( const entry of filteredLoggerEntries ) {
2666
+ const text = entry.textContent;
2667
+ const fields = [];
2668
+ let i = 0;
2669
+ let beg = text.indexOf('\t');
2670
+ if ( beg === 0 ) { continue; }
2671
+ let timeField = text.slice(0, beg);
2672
+ if ( options.time === 'anonymous' ) {
2673
+ timeField = '+' + Math.round((entry.tstamp - t0) / 1000).toString();
2674
+ }
2675
+ fields.push(timeField);
2676
+ beg += 1;
2677
+ while ( beg < text.length ) {
2678
+ let end = text.indexOf('\t', beg);
2679
+ if ( end === -1 ) { end = text.length; }
2680
+ fields.push(text.slice(beg, end));
2681
+ beg = end + 1;
2682
+ i += 1;
2683
+ }
2684
+ lines.push(fields);
2685
+ }
2686
+ };
2687
+
2688
+ const formatAsPlainTextTable = function() {
2689
+ const outputAll = [];
2690
+ for ( const fields of lines ) {
2691
+ outputAll.push(fields.join('\t'));
2692
+ }
2693
+ outputAll.push('');
2694
+ return outputAll.join('\n');
2695
+ };
2696
+
2697
+ const formatAsMarkdownTable = function() {
2698
+ const outputAll = [];
2699
+ let fieldCount = 0;
2700
+ for ( const fields of lines ) {
2701
+ if ( fields.length <= 2 ) { continue; }
2702
+ if ( fields.length > fieldCount ) {
2703
+ fieldCount = fields.length;
2704
+ }
2705
+ const outputOne = [];
2706
+ for ( let i = 0; i < fields.length; i++ ) {
2707
+ const field = fields[i];
2708
+ let code = /\b(?:www\.|https?:\/\/)/.test(field) ? '`' : '';
2709
+ outputOne.push(` ${code}${field.replace(/\|/g, '\\|')}${code} `);
2710
+ }
2711
+ outputAll.push(outputOne.join('|'));
2712
+ }
2713
+ if ( fieldCount !== 0 ) {
2714
+ outputAll.unshift(
2715
+ `${' |'.repeat(fieldCount-1)} `,
2716
+ `${':--- |'.repeat(fieldCount-1)}:--- `
2717
+ );
2718
+ }
2719
+ return `<details><summary>Logger output</summary>\n\n|${outputAll.join('|\n|')}|\n</details>\n`;
2720
+ };
2721
+
2722
+ const formatAsTable = function() {
2723
+ if ( options.encoding === 'plain' ) {
2724
+ return formatAsPlainTextTable();
2725
+ }
2726
+ return formatAsMarkdownTable();
2727
+ };
2728
+
2729
+ const formatAsList = function() {
2730
+ const outputAll = [];
2731
+ for ( const fields of lines ) {
2732
+ const outputOne = [];
2733
+ for ( let i = 0; i < fields.length; i++ ) {
2734
+ let str = fields[i];
2735
+ if ( str.length === 0 ) { continue; }
2736
+ outputOne.push(str);
2737
+ }
2738
+ outputAll.push(outputOne.join('\n'));
2739
+ }
2740
+ let before, between, after;
2741
+ if ( options.encoding === 'markdown' ) {
2742
+ const code = '```';
2743
+ before = `<details><summary>Logger output</summary>\n\n${code}\n`;
2744
+ between = `\n${code}\n${code}\n`;
2745
+ after = `\n${code}\n</details>\n`;
2746
+ } else {
2747
+ before = '';
2748
+ between = '\n\n';
2749
+ after = '\n';
2750
+ }
2751
+ return `${before}${outputAll.join(between)}${after}`;
2752
+ };
2753
+
2754
+ const format = function() {
2755
+ const output = qs$(dialog, '.output');
2756
+ if ( options.format === 'list' ) {
2757
+ output.textContent = formatAsList();
2758
+ } else {
2759
+ output.textContent = formatAsTable();
2760
+ }
2761
+ };
2762
+
2763
+ const setRadioButton = function(group, value) {
2764
+ if ( options.hasOwnProperty(group) === false ) { return; }
2765
+ const groupEl = qs$(dialog, `[data-radio="${group}"]`);
2766
+ const buttonEls = qsa$(groupEl, '[data-radio-item]');
2767
+ for ( const buttonEl of buttonEls ) {
2768
+ dom.cl.toggle(
2769
+ buttonEl,
2770
+ 'on',
2771
+ dom.attr(buttonEl, 'data-radio-item') === value
2772
+ );
2773
+ }
2774
+ options[group] = value;
2775
+ };
2776
+
2777
+ const onOption = function(ev) {
2778
+ const target = ev.target.closest('span[data-i18n]');
2779
+ if ( target === null ) { return; }
2780
+
2781
+ // Copy to clipboard
2782
+ if ( target.matches('.pushbutton') ) {
2783
+ const textarea = qs$(dialog, 'textarea');
2784
+ textarea.focus();
2785
+ if ( textarea.selectionEnd === textarea.selectionStart ) {
2786
+ textarea.select();
2787
+ }
2788
+ document.execCommand('copy');
2789
+ ev.stopPropagation();
2790
+ return;
2791
+ }
2792
+
2793
+ // Radio buttons
2794
+ const group = target.closest('[data-radio]');
2795
+ if ( group === null ) { return; }
2796
+ if ( target.matches('span.on') ) { return; }
2797
+ const item = target.closest('[data-radio-item]');
2798
+ if ( item === null ) { return; }
2799
+ setRadioButton(
2800
+ dom.attr(group, 'data-radio'),
2801
+ dom.attr(item, 'data-radio-item')
2802
+ );
2803
+ format();
2804
+ ev.stopPropagation();
2805
+ };
2806
+
2807
+ const toggleOn = function() {
2808
+ dialog = modalDialog.create(
2809
+ '#loggerExportDialog',
2810
+ ( ) => {
2811
+ dialog = undefined;
2812
+ lines.length = 0;
2813
+ }
2814
+ );
2815
+
2816
+ setRadioButton('format', options.format);
2817
+ setRadioButton('encoding', options.encoding);
2818
+
2819
+ collectLines();
2820
+ format();
2821
+
2822
+ dom.on(qs$(dialog, '.options'), 'click', onOption, { capture: true });
2823
+
2824
+ modalDialog.show();
2825
+ };
2826
+
2827
+ dom.on('#loggerExport', 'click', toggleOn);
2828
+ })();
2829
+
2830
+ /******************************************************************************/
2831
+
2832
+ // TODO:
2833
+ // - Give some thoughts to:
2834
+ // - an option to discard immediately filtered out new entries
2835
+ // - max entry count _per load_
2836
+ //
2837
+ const loggerSettings = (( ) => {
2838
+ const settings = {
2839
+ discard: {
2840
+ maxAge: 240, // global
2841
+ maxEntryCount: 2000, // per-tab
2842
+ maxLoadCount: 20, // per-tab
2843
+ },
2844
+ columns: [ true, true, true, true, true, true, true, true, true ],
2845
+ linesPerEntry: 4,
2846
+ };
2847
+
2848
+ vAPI.localStorage.getItemAsync('loggerSettings').then(value => {
2849
+ try {
2850
+ const stored = JSON.parse(value);
2851
+ if ( typeof stored.discard.maxAge === 'number' ) {
2852
+ settings.discard.maxAge = stored.discard.maxAge;
2853
+ }
2854
+ if ( typeof stored.discard.maxEntryCount === 'number' ) {
2855
+ settings.discard.maxEntryCount = stored.discard.maxEntryCount;
2856
+ }
2857
+ if ( typeof stored.discard.maxLoadCount === 'number' ) {
2858
+ settings.discard.maxLoadCount = stored.discard.maxLoadCount;
2859
+ }
2860
+ if ( typeof stored.linesPerEntry === 'number' ) {
2861
+ settings.linesPerEntry = stored.linesPerEntry;
2862
+ }
2863
+ if ( Array.isArray(stored.columns) ) {
2864
+ settings.columns = stored.columns;
2865
+ }
2866
+ } catch(ex) {
2867
+ }
2868
+ });
2869
+
2870
+ const valueFromInput = function(input, def) {
2871
+ let value = parseInt(input.value, 10);
2872
+ if ( isNaN(value) ) { value = def; }
2873
+ const min = parseInt(dom.attr(input, 'min'), 10);
2874
+ if ( isNaN(min) === false ) {
2875
+ value = Math.max(value, min);
2876
+ }
2877
+ const max = parseInt(dom.attr(input, 'max'), 10);
2878
+ if ( isNaN(max) === false ) {
2879
+ value = Math.min(value, max);
2880
+ }
2881
+ return value;
2882
+ };
2883
+
2884
+ const toggleOn = function() {
2885
+ const dialog = modalDialog.create(
2886
+ '#loggerSettingsDialog',
2887
+ dialog => {
2888
+ toggleOff(dialog);
2889
+ }
2890
+ );
2891
+
2892
+ // Number inputs
2893
+ let inputs = qsa$(dialog, 'input[type="number"]');
2894
+ inputs[0].value = settings.discard.maxAge;
2895
+ inputs[1].value = settings.discard.maxLoadCount;
2896
+ inputs[2].value = settings.discard.maxEntryCount;
2897
+ inputs[3].value = settings.linesPerEntry;
2898
+ dom.on(inputs[3], 'input', ev => {
2899
+ settings.linesPerEntry = valueFromInput(ev.target, 4);
2900
+ viewPort.updateLayout();
2901
+ });
2902
+
2903
+ // Column checkboxs
2904
+ const onColumnChanged = ev => {
2905
+ const input = ev.target;
2906
+ const i = parseInt(dom.attr(input, 'data-column'), 10);
2907
+ settings.columns[i] = input.checked !== true;
2908
+ viewPort.updateLayout();
2909
+ };
2910
+ inputs = qsa$(dialog, 'input[type="checkbox"][data-column]');
2911
+ for ( const input of inputs ) {
2912
+ const i = parseInt(dom.attr(input, 'data-column'), 10);
2913
+ input.checked = settings.columns[i] === false;
2914
+ dom.on(input, 'change', onColumnChanged);
2915
+ }
2916
+
2917
+ modalDialog.show();
2918
+ };
2919
+
2920
+ const toggleOff = function(dialog) {
2921
+ // Number inputs
2922
+ let inputs = qsa$(dialog, 'input[type="number"]');
2923
+ settings.discard.maxAge = valueFromInput(inputs[0], 240);
2924
+ settings.discard.maxLoadCount = valueFromInput(inputs[1], 25);
2925
+ settings.discard.maxEntryCount = valueFromInput(inputs[2], 2000);
2926
+ settings.linesPerEntry = valueFromInput(inputs[3], 4);
2927
+
2928
+ // Column checkboxs
2929
+ inputs = qsa$(dialog, 'input[type="checkbox"][data-column]');
2930
+ for ( const input of inputs ) {
2931
+ const i = parseInt(dom.attr(input, 'data-column'), 10);
2932
+ settings.columns[i] = input.checked !== true;
2933
+ }
2934
+
2935
+ vAPI.localStorage.setItem(
2936
+ 'loggerSettings',
2937
+ JSON.stringify(settings)
2938
+ );
2939
+
2940
+ viewPort.updateLayout();
2941
+ };
2942
+
2943
+ dom.on('#loggerSettings', 'click', toggleOn);
2944
+
2945
+ return settings;
2946
+ })();
2947
+
2948
+ /******************************************************************************/
2949
+
2950
+ logger.resize = (function() {
2951
+ let timer;
2952
+
2953
+ const resize = function() {
2954
+ const vrect = dom.body.getBoundingClientRect();
2955
+ for ( const elem of qsa$('.vscrollable') ) {
2956
+ const crect = elem.getBoundingClientRect();
2957
+ const dh = crect.bottom - vrect.bottom;
2958
+ if ( dh === 0 ) { continue; }
2959
+ elem.style.height = Math.ceil(crect.height - dh) + 'px';
2960
+ }
2961
+ };
2962
+
2963
+ const resizeAsync = function() {
2964
+ if ( timer !== undefined ) { return; }
2965
+ timer = self.requestAnimationFrame(( ) => {
2966
+ timer = undefined;
2967
+ resize();
2968
+ });
2969
+ };
2970
+
2971
+ resizeAsync();
2972
+
2973
+ dom.on(window, 'resize', resizeAsync, { passive: true });
2974
+
2975
+ return resizeAsync;
2976
+ })();
2977
+
2978
+ /******************************************************************************/
2979
+
2980
+ const grabView = function() {
2981
+ if ( logger.ownerId === undefined ) {
2982
+ logger.ownerId = Date.now();
2983
+ }
2984
+ readLogBuffer();
2985
+ };
2986
+
2987
+ const releaseView = function() {
2988
+ if ( logger.ownerId === undefined ) { return; }
2989
+ vAPI.messaging.send('loggerUI', {
2990
+ what: 'releaseView',
2991
+ ownerId: logger.ownerId,
2992
+ });
2993
+ logger.ownerId = undefined;
2994
+ };
2995
+
2996
+ dom.on(window, 'pagehide', releaseView);
2997
+ dom.on(window, 'pageshow', grabView);
2998
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1398625
2999
+ dom.on(window, 'beforeunload', releaseView);
3000
+
3001
+ /******************************************************************************/
3002
+
3003
+ dom.on('#pageSelector', 'change', pageSelectorChanged);
3004
+ dom.on('#netInspector .vCompactToggler', 'click', toggleVCompactView);
3005
+ dom.on('#pause', 'click', pauseNetInspector);
3006
+
3007
+ // https://github.com/gorhill/uBlock/issues/507
3008
+ // Ensure tab selector is in sync with URL hash
3009
+ pageSelectorFromURLHash();
3010
+ dom.on(window, 'hashchange', pageSelectorFromURLHash);
3011
+
3012
+ // Start to watch the current window geometry 2 seconds after the document
3013
+ // is loaded, to be sure no spurious geometry changes will be triggered due
3014
+ // to the window geometry pontentially not settling fast enough.
3015
+ if ( self.location.search.includes('popup=1') ) {
3016
+ dom.on(window, 'load', ( ) => {
3017
+ vAPI.defer.once(2000).then(( ) => {
3018
+ popupLoggerBox = {
3019
+ x: self.screenX,
3020
+ y: self.screenY,
3021
+ w: self.outerWidth,
3022
+ h: self.outerHeight,
3023
+ };
3024
+ });
3025
+ }, { once: true });
3026
+ }
3027
+
3028
+ /******************************************************************************/