|
26 | 26 | /*! © DuckDuckGo ContentScopeScripts protections https://github.com/duckduckgo/content-scope-scripts/ */
|
27 | 27 | (function() {
|
28 | 28 | "use strict";
|
29 |
| - var _bundledConfig, _trackerLookup, _documentOriginIsTracker, _bundledfeatureSettings, _messaging, _isDebugFlagSet, _args, _tagName, _el, _listeners, _connected, _sinks, _debug; |
| 29 | + var _bundledConfig, _trackerLookup, _documentOriginIsTracker, _bundledfeatureSettings, _messaging, _isDebugFlagSet, _args, _activeShareRequest, _tagName, _el, _listeners, _connected, _sinks, _debug; |
30 | 30 | const Set$1 = globalThis.Set;
|
31 | 31 | const Reflect$1 = globalThis.Reflect;
|
32 | 32 | globalThis.customElements?.get.bind(globalThis.customElements);
|
33 | 33 | globalThis.customElements?.define.bind(globalThis.customElements);
|
34 | 34 | const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
35 | 35 | const objectKeys = Object.keys;
|
| 36 | + const URL$1 = globalThis.URL; |
36 | 37 | let globalObj = typeof window === "undefined" ? globalThis : window;
|
37 | 38 | let Error$1 = globalObj.Error;
|
38 | 39 | let messageSecret;
|
|
529 | 530 | [
|
530 | 531 | "clickToLoad",
|
531 | 532 | "cookie",
|
532 |
| - "windowsPermissionUsage", |
533 |
| - "webCompat", |
534 | 533 | "duckPlayer",
|
535 |
| - "harmfulApis" |
| 534 | + "harmfulApis", |
| 535 | + "webCompat", |
| 536 | + "windowsPermissionUsage" |
536 | 537 | ]
|
537 | 538 | );
|
538 | 539 | const platformSupport = {
|
|
2282 | 2283 | window.outerHeight = window.innerHeight;
|
2283 | 2284 | window.outerWidth = window.innerWidth;
|
2284 | 2285 | }
|
| 2286 | + const MSG_WEB_SHARE = "webShare"; |
| 2287 | + function canShare(data) { |
| 2288 | + if (typeof data !== "object") |
| 2289 | + return false; |
| 2290 | + if (!("url" in data) && !("title" in data) && !("text" in data)) |
| 2291 | + return false; |
| 2292 | + if ("files" in data) |
| 2293 | + return false; |
| 2294 | + if ("title" in data && typeof data.title !== "string") |
| 2295 | + return false; |
| 2296 | + if ("text" in data && typeof data.text !== "string") |
| 2297 | + return false; |
| 2298 | + if ("url" in data) { |
| 2299 | + if (typeof data.url !== "string") |
| 2300 | + return false; |
| 2301 | + try { |
| 2302 | + const url = new URL$1(data.url, location.href); |
| 2303 | + if (url.protocol !== "http:" && url.protocol !== "https:") |
| 2304 | + return false; |
| 2305 | + } catch (err) { |
| 2306 | + return false; |
| 2307 | + } |
| 2308 | + } |
| 2309 | + if (window !== window.top) |
| 2310 | + return false; |
| 2311 | + return true; |
| 2312 | + } |
| 2313 | + function cleanShareData(data) { |
| 2314 | + const dataToSend = {}; |
| 2315 | + for (const key of ["title", "text", "url"]) { |
| 2316 | + if (key in data) |
| 2317 | + dataToSend[key] = data[key]; |
| 2318 | + } |
| 2319 | + if ("url" in data) { |
| 2320 | + dataToSend.url = new URL$1(data.url, location.href).href; |
| 2321 | + } |
| 2322 | + if ("url" in dataToSend && "text" in dataToSend) { |
| 2323 | + dataToSend.text = `${dataToSend.text} ${dataToSend.url}`; |
| 2324 | + delete dataToSend.url; |
| 2325 | + } |
| 2326 | + if (!("url" in dataToSend) && !("text" in dataToSend)) { |
| 2327 | + dataToSend.text = ""; |
| 2328 | + } |
| 2329 | + return dataToSend; |
| 2330 | + } |
2285 | 2331 | class WebCompat extends ContentFeature {
|
| 2332 | + constructor() { |
| 2333 | + super(...arguments); |
| 2334 | + /** @type {Promise<any> | null} */ |
| 2335 | + __privateAdd(this, _activeShareRequest, null); |
| 2336 | + } |
2286 | 2337 | init() {
|
2287 | 2338 | if (this.getFeatureSettingEnabled("windowSizing")) {
|
2288 | 2339 | windowSizingFix();
|
|
2312 | 2363 | if (this.getFeatureSettingEnabled("presentation")) {
|
2313 | 2364 | this.presentationFix();
|
2314 | 2365 | }
|
| 2366 | + if (this.getFeatureSettingEnabled("webShare")) { |
| 2367 | + this.shimWebShare(); |
| 2368 | + } |
| 2369 | + if (this.getFeatureSettingEnabled("viewportWidth")) { |
| 2370 | + this.viewportWidthFix(); |
| 2371 | + } |
| 2372 | + } |
| 2373 | + /** Shim Web Share API in Android WebView */ |
| 2374 | + shimWebShare() { |
| 2375 | + if (typeof navigator.canShare === "function" || typeof navigator.share === "function") |
| 2376 | + return; |
| 2377 | + this.defineProperty(Navigator.prototype, "canShare", { |
| 2378 | + configurable: true, |
| 2379 | + enumerable: true, |
| 2380 | + writable: true, |
| 2381 | + value: canShare |
| 2382 | + }); |
| 2383 | + this.defineProperty(Navigator.prototype, "share", { |
| 2384 | + configurable: true, |
| 2385 | + enumerable: true, |
| 2386 | + writable: true, |
| 2387 | + value: async (data) => { |
| 2388 | + if (!canShare(data)) |
| 2389 | + return Promise.reject(new TypeError("Invalid share data")); |
| 2390 | + if (__privateGet(this, _activeShareRequest)) { |
| 2391 | + return Promise.reject(new DOMException("Share already in progress", "InvalidStateError")); |
| 2392 | + } |
| 2393 | + if (!navigator.userActivation.isActive) { |
| 2394 | + return Promise.reject(new DOMException("Share must be initiated by a user gesture", "InvalidStateError")); |
| 2395 | + } |
| 2396 | + const dataToSend = cleanShareData(data); |
| 2397 | + __privateSet(this, _activeShareRequest, this.messaging.request(MSG_WEB_SHARE, dataToSend)); |
| 2398 | + let resp; |
| 2399 | + try { |
| 2400 | + resp = await __privateGet(this, _activeShareRequest); |
| 2401 | + } catch (err) { |
| 2402 | + throw new DOMException(err.message, "DataError"); |
| 2403 | + } finally { |
| 2404 | + __privateSet(this, _activeShareRequest, null); |
| 2405 | + } |
| 2406 | + if (resp.failure) { |
| 2407 | + switch (resp.failure.name) { |
| 2408 | + case "AbortError": |
| 2409 | + case "NotAllowedError": |
| 2410 | + case "DataError": |
| 2411 | + throw new DOMException(resp.failure.message, resp.failure.name); |
| 2412 | + default: |
| 2413 | + throw new DOMException(resp.failure.message, "DataError"); |
| 2414 | + } |
| 2415 | + } |
| 2416 | + } |
| 2417 | + }); |
2315 | 2418 | }
|
2316 | 2419 | /**
|
2317 | 2420 | * Notification fix for adding missing API for Android WebView.
|
|
2626 | 2729 | messageHandlers: proxy
|
2627 | 2730 | };
|
2628 | 2731 | }
|
| 2732 | + viewportWidthFix() { |
| 2733 | + const viewportTag = document.querySelector("meta[name=viewport]"); |
| 2734 | + if (!viewportTag) |
| 2735 | + return; |
| 2736 | + const viewportContent = viewportTag.getAttribute("content"); |
| 2737 | + if (!viewportContent) |
| 2738 | + return; |
| 2739 | + const viewportContentParts = viewportContent.split(","); |
| 2740 | + const widthPart = viewportContentParts.find((part) => part.includes("width")); |
| 2741 | + if (widthPart) |
| 2742 | + return; |
| 2743 | + viewportTag.setAttribute("content", `${viewportContent},width=device-width`); |
| 2744 | + } |
2629 | 2745 | }
|
| 2746 | + _activeShareRequest = new WeakMap(); |
2630 | 2747 | function generateUniqueID() {
|
2631 | 2748 | return Symbol(void 0);
|
2632 | 2749 | }
|
|
0 commit comments