Skip to content

Commit ff90745

Browse files
Merge branch 'main' into dependabot/npm_and_yarn/main/atlaskit/pragmatic-drag-and-drop-1.7.4
2 parents eb11bf9 + 1c0f07c commit ff90745

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1873
-336
lines changed

.github/workflows/snapshots.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ on:
1010
branches:
1111
- main
1212
pull_request:
13+
merge_group:
1314

1415
permissions:
1516
contents: read

.github/workflows/tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
branches:
66
- main
77
pull_request:
8+
merge_group:
89

910
permissions:
1011
contents: read

injected/docs/platform-integration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ The following is a guideline for when using native JavaScript syntax or built-in
2424

2525
#### Android
2626

27-
- **Android 23** (minimum) - [Product feedback request: Android - min supported version](https://app.asana.com/1/137249556945/project/908478224964033/task/1209367367171662?focus=true)
27+
- **Android 23** (minimum) - [Product feedback request: Android - min supported version](https://app.asana.com/1/137249556945/project/1175293949586521/task/1200982924050797?focus=true)
2828
- **Chrome 80+** (minimum)
2929
- **Reference**: See [pixel dashboard](https://app.asana.com/1/137249556945/project/908478224964033/task/1209367367171662?focus=true)
3030

injected/src/features.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const otherFeatures = /** @type {const} */ ([
2929
'breakageReporting',
3030
'autofillPasswordImport',
3131
'favicon',
32+
'webTelemetry',
3233
'scriptlets',
3334
]);
3435

@@ -51,6 +52,7 @@ export const platformSupport = {
5152
windows: [
5253
'cookie',
5354
...baseFeatures,
55+
'webTelemetry',
5456
'windowsPermissionUsage',
5557
'duckPlayer',
5658
'brokerProtection',
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
import ContentFeature from '../content-feature.js';
2+
3+
const MSG_VIDEO_PLAYBACK = 'video-playback';
4+
5+
export class WebTelemetry extends ContentFeature {
6+
constructor(featureName, importConfig, args) {
7+
super(featureName, importConfig, args);
8+
this.seenVideoElements = new WeakSet();
9+
this.seenVideoUrls = new Set();
10+
}
11+
12+
init() {
13+
if (this.getFeatureSettingEnabled('videoPlayback')) {
14+
this.videoPlaybackObserve();
15+
}
16+
}
17+
18+
getVideoUrl(video) {
19+
// Try to get the video URL from various sources
20+
if (video.src) {
21+
return video.src;
22+
}
23+
if (video.currentSrc) {
24+
return video.currentSrc;
25+
}
26+
// Check for source elements
27+
const source = video.querySelector('source');
28+
if (source && source.src) {
29+
return source.src;
30+
}
31+
return null;
32+
}
33+
34+
fireTelemetryForVideo(video) {
35+
const videoUrl = this.getVideoUrl(video);
36+
if (this.seenVideoUrls.has(videoUrl)) {
37+
return;
38+
}
39+
// If we have a URL, store it just to deduplicate
40+
// This will clear on page change and isn't sent to native/server.
41+
if (videoUrl) {
42+
this.seenVideoUrls.add(videoUrl);
43+
}
44+
const message = {
45+
userInteraction: navigator.userActivation.isActive,
46+
};
47+
this.messaging.notify(MSG_VIDEO_PLAYBACK, message);
48+
}
49+
50+
addPlayObserver(video) {
51+
if (this.seenVideoElements.has(video)) {
52+
return; // already observed
53+
}
54+
this.seenVideoElements.add(video);
55+
video.addEventListener('play', () => this.fireTelemetryForVideo(video));
56+
}
57+
58+
addListenersToAllVideos(node) {
59+
if (!node) {
60+
return;
61+
}
62+
const videos = node.querySelectorAll('video');
63+
videos.forEach((video) => {
64+
this.addPlayObserver(video);
65+
});
66+
}
67+
68+
videoPlaybackObserve() {
69+
if (document.body) {
70+
this.setup();
71+
} else {
72+
window.addEventListener(
73+
'DOMContentLoaded',
74+
() => {
75+
this.setup();
76+
},
77+
{ once: true },
78+
);
79+
}
80+
}
81+
82+
setup() {
83+
const documentBody = document.body;
84+
if (!documentBody) return;
85+
86+
this.addListenersToAllVideos(documentBody);
87+
88+
// Backfill: fire telemetry for already playing videos
89+
documentBody.querySelectorAll('video').forEach((video) => {
90+
if (!video.paused && !video.ended) {
91+
this.fireTelemetryForVideo(video);
92+
}
93+
});
94+
95+
const observerCallback = (mutationsList) => {
96+
for (const mutation of mutationsList) {
97+
if (mutation.type === 'childList') {
98+
mutation.addedNodes.forEach((node) => {
99+
if (node.nodeType === Node.ELEMENT_NODE) {
100+
if (node.tagName === 'VIDEO') {
101+
this.addPlayObserver(node);
102+
} else {
103+
this.addListenersToAllVideos(node);
104+
}
105+
}
106+
});
107+
}
108+
}
109+
};
110+
const observer = new MutationObserver(observerCallback);
111+
observer.observe(documentBody, {
112+
childList: true,
113+
subtree: true,
114+
});
115+
}
116+
}
117+
118+
export default WebTelemetry;

injected/src/utils.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ let globalObj = typeof window === 'undefined' ? globalThis : window;
77
let Error = globalObj.Error;
88
let messageSecret;
99

10+
let isAppleSiliconCache = null;
11+
1012
// save a reference to original CustomEvent amd dispatchEvent so they can't be overriden to forge messages
1113
export const OriginalCustomEvent = typeof CustomEvent === 'undefined' ? null : CustomEvent;
1214
export const originalWindowDispatchEvent = typeof window === 'undefined' ? null : window.dispatchEvent.bind(window);
@@ -258,13 +260,18 @@ export function camelcase(dashCaseText) {
258260

259261
// We use this method to detect M1 macs and set appropriate API values to prevent sites from detecting fingerprinting protections
260262
function isAppleSilicon() {
263+
// Cache the result since hardware doesn't change
264+
if (isAppleSiliconCache !== null) {
265+
return isAppleSiliconCache;
266+
}
261267
const canvas = document.createElement('canvas');
262268
const gl = canvas.getContext('webgl');
263269

264270
// Best guess if the device is an Apple Silicon
265271
// https://stackoverflow.com/a/65412357
266-
// @ts-expect-error - Object is possibly 'null'
267-
return gl.getSupportedExtensions().indexOf('WEBGL_compressed_texture_etc') !== -1;
272+
const compressedTextureValue = gl?.getSupportedExtensions()?.indexOf('WEBGL_compressed_texture_etc');
273+
isAppleSiliconCache = typeof compressedTextureValue === 'number' && compressedTextureValue !== -1;
274+
return isAppleSiliconCache;
268275
}
269276

270277
/**
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import fs from 'fs';
2+
import path from 'path';
3+
import { fileURLToPath } from 'url';
4+
5+
describe('Dependency format check', () => {
6+
it('should use a 13-digit numeric tag (not a commit hash or short hash) for @duckduckgo/privacy-configuration', () => {
7+
const __filename = fileURLToPath(import.meta.url);
8+
const __dirname = path.dirname(__filename);
9+
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '../package.json'), 'utf-8'));
10+
const dep = pkg.dependencies['@duckduckgo/privacy-configuration'];
11+
// Only allow 13-digit numeric tags and not a commit hash or short hash
12+
expect(dep).toMatch(/^github:duckduckgo\/privacy-configuration#\d{13}$/);
13+
});
14+
});

special-pages/pages/new-tab/app/components/App.module.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ body[data-animate-background="true"] {
3232
max-width: calc(504 * var(--px-in-rem));
3333
}
3434

35+
:global([data-entry-point="omnibar"]) {
36+
max-width: calc(620 * var(--px-in-rem));
37+
}
38+
3539
:global(.vertical-space) {
3640
padding-top: 1rem;
3741
padding-bottom: 1rem;

special-pages/pages/new-tab/app/components/Icons.js

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ export function BackChevron() {
170170
*/
171171
export function SearchIcon(props) {
172172
return (
173-
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
173+
<svg width="16" height="16" fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
174174
<g clip-path="url(#Find-Search-16_svg__a)">
175175
<path
176176
fill="currentColor"
@@ -194,7 +194,7 @@ export function SearchIcon(props) {
194194
*/
195195
export function SearchColorIcon(props) {
196196
return (
197-
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
197+
<svg width="16" height="16" fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
198198
<g clip-path="url(#Search-Find-Color-16_svg__a)">
199199
<path fill="#ADC2FC" d="M12 7A5 5 0 1 1 2 7a5 5 0 0 1 10 0Z" />
200200
<path fill="#fff" d="M7 2a4.98 4.98 0 0 1 3.403 1.338 5.5 5.5 0 0 0-7.065 7.065A5 5 0 0 1 7 2Z" opacity=".5" />
@@ -218,7 +218,7 @@ export function SearchColorIcon(props) {
218218
*/
219219
export function AiChatIcon(props) {
220220
return (
221-
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
221+
<svg width="16" height="16" fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
222222
<g fill="currentColor" clip-path="url(#Ai-Chat-16_svg__a)">
223223
<path
224224
fill-rule="evenodd"
@@ -242,7 +242,7 @@ export function AiChatIcon(props) {
242242
*/
243243
export function AiChatColorIcon(props) {
244244
return (
245-
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
245+
<svg width="16" height="16" fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
246246
<g clip-path="url(#Ai-Chat-Gradient-Color-16_svg__a)">
247247
<path
248248
fill="url(#Ai-Chat-Gradient-Color-16_svg__b)"
@@ -292,7 +292,7 @@ export function AiChatColorIcon(props) {
292292
*/
293293
export function ArrowRightIcon(props) {
294294
return (
295-
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
295+
<svg width="16" height="16" fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
296296
<path
297297
fill="currentColor"
298298
d="M8.187 1.689a.625.625 0 0 1 .885-.884l5.31 5.316c.83.83.83 2.174 0 3.004l-5.31 5.315a.625.625 0 0 1-.885-.884l5.305-5.308H.625a.625.625 0 1 1 0-1.25h12.867z"
@@ -307,7 +307,7 @@ export function ArrowRightIcon(props) {
307307
*/
308308
export function GlobeIcon(props) {
309309
return (
310-
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
310+
<svg width="16" height="16" fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
311311
<g clip-path="url(#Globe-16_svg__a)">
312312
<path
313313
fill="currentColor"
@@ -331,7 +331,7 @@ export function GlobeIcon(props) {
331331
*/
332332
export function HistoryIcon(props) {
333333
return (
334-
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
334+
<svg width="16" height="16" fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
335335
<g fill="currentColor" clip-path="url(#History-16_svg__a)">
336336
<path d="m2.072 4.918-.08-.004A6.753 6.753 0 1 1 1.246 8 .623.623 0 1 0 0 8a8 8 0 1 0 1.247-4.29V1.115a.623.623 0 0 0-1.247 0v2.977c0 1.145.928 2.072 2.072 2.072h2.486a.623.623 0 0 0 0-1.246z" />
337337
<path d="M8.625 3.625a.625.625 0 1 0-1.25 0V8c0 .166.066.325.183.442l2.375 2.375a.625.625 0 1 0 .884-.884L8.625 7.741z" />
@@ -351,7 +351,7 @@ export function HistoryIcon(props) {
351351
*/
352352
export function FavoriteIcon(props) {
353353
return (
354-
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
354+
<svg width="16" height="16" fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
355355
<g clip-path="url(#Favorite-16_svg__a)">
356356
<path
357357
fill="currentColor"
@@ -375,7 +375,7 @@ export function FavoriteIcon(props) {
375375
*/
376376
export function BookmarkIcon(props) {
377377
return (
378-
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
378+
<svg width="16" height="16" fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
379379
<g clip-path="url(#Bookmark-16_svg__a)">
380380
<path
381381
fill="currentColor"
@@ -399,15 +399,15 @@ export function BookmarkIcon(props) {
399399
*/
400400
export function BrowserIcon(props) {
401401
return (
402-
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
402+
<svg width="16" height="16" fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
403403
<path
404-
fill="#000"
404+
fill="currentColor"
405405
fill-rule="evenodd"
406406
d="M0 5a4 4 0 0 1 4-4h8a4 4 0 0 1 4 4v1.792c0 .478-.681.721-1.053.422a.52.52 0 0 1-.197-.4v-.819H1.25V11A2.75 2.75 0 0 0 4 13.75h2.135a.57.57 0 0 1 .497.312c.21.398-.055.938-.506.938H4a4 4 0 0 1-4-4zm1.262-.255h13.476A2.75 2.75 0 0 0 12 2.25H4a2.75 2.75 0 0 0-2.738 2.495"
407407
clip-rule="evenodd"
408408
/>
409409
<path
410-
fill="#000"
410+
fill="currentColor"
411411
fill-rule="evenodd"
412412
d="M11.5 7a4.5 4.5 0 1 0 0 9 4.5 4.5 0 0 0 0-9m-1.972 7.084A3.25 3.25 0 0 1 8.288 12h.85a7.6 7.6 0 0 0 .39 2.084M8.337 10.75h.818a7.5 7.5 0 0 1 .373-1.834 3.25 3.25 0 0 0-1.191 1.834m2.495 3.233c-.226-.5-.392-1.19-.441-1.983h2.218c-.05.793-.215 1.482-.441 1.983-.299.66-.583.767-.668.767s-.37-.106-.668-.767m0-4.966c-.202.447-.356 1.045-.422 1.733h2.18c-.066-.688-.22-1.286-.422-1.733-.299-.66-.583-.767-.668-.767s-.37.106-.668.767m2.64 5.067c.213-.606.348-1.32.39-2.084h.85a3.25 3.25 0 0 1-1.24 2.084m.373-3.334h.818a3.25 3.25 0 0 0-1.19-1.834c.188.54.316 1.164.371 1.834Z"
413413
clip-rule="evenodd"
@@ -416,6 +416,21 @@ export function BrowserIcon(props) {
416416
);
417417
}
418418

419+
/**
420+
* From https://dub.duckduckgo.com/duckduckgo/Icons/blob/Main/Glyphs/16px/Tab-Desktop-16.svg
421+
* @param {import('preact').JSX.SVGAttributes<SVGSVGElement>} props
422+
*/
423+
export function TabDesktopIcon(props) {
424+
return (
425+
<svg width="16" height="16" fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" {...props}>
426+
<path
427+
fill="currentColor"
428+
d="M11 2a4 4 0 0 1 4 4v4c0 .854.39 1.617 1 2.121v.357c0 .517-.541.841-.925.495A4 4 0 0 1 13.75 10V6A2.75 2.75 0 0 0 11 3.25H5A2.75 2.75 0 0 0 2.25 6v4a4 4 0 0 1-1.325 2.973c-.384.346-.925.022-.925-.495v-.357c.61-.504 1-1.267 1-2.121V6a4 4 0 0 1 4-4z"
429+
/>
430+
</svg>
431+
);
432+
}
433+
419434
/**
420435
* @param {import('preact').JSX.SVGAttributes<SVGSVGElement>} props
421436
*/

special-pages/pages/new-tab/app/customizer/CustomizerProvider.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ import { applyDefaultStyles } from './utils.js';
1414
* @typedef {import('../service.hooks.js').Events<CustomizerData, undefined>} Events
1515
*/
1616

17+
/**
18+
* @typedef {{
19+
* title: string,
20+
* icon: import('preact').ComponentChild,
21+
* onClick: () => void,
22+
* }} SettingsLinkData
23+
*/
24+
1725
/**
1826
* These are the values exposed to consumers.
1927
*/
@@ -47,6 +55,10 @@ export const CustomizerContext = createContext({
4755
* @param {UserImageContextMenu} _params
4856
*/
4957
customizerContextMenu: (_params) => {},
58+
/**
59+
* @type {import('@preact/signals').Signal<Record<string, SettingsLinkData>>}
60+
*/
61+
settingsLinks: signal({}),
5062
});
5163

5264
/**
@@ -126,8 +138,11 @@ export function CustomizerProvider({ service, initialData, children }) {
126138
/** @type {(p: UserImageContextMenu) => void} */
127139
const customizerContextMenu = useCallback((params) => service.contextMenu(params), [service]);
128140

141+
/** @type {import('@preact/signals').Signal<Record<string, SettingsLinkData>>} */
142+
const settingsLinks = useSignal({});
143+
129144
return (
130-
<CustomizerContext.Provider value={{ data, select, upload, setTheme, deleteImage, customizerContextMenu }}>
145+
<CustomizerContext.Provider value={{ data, select, upload, setTheme, deleteImage, customizerContextMenu, settingsLinks }}>
131146
<CustomizerThemesContext.Provider value={{ main, browser }}>{children}</CustomizerThemesContext.Provider>
132147
</CustomizerContext.Provider>
133148
);

0 commit comments

Comments
 (0)