diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index bce1fedf898d..91934e09276d 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "2.48.0"
+ ".": "2.49.0"
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 088457294820..0a7fcea8b4e5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,40 @@
# Changelog
+## [2.49.0](https://github.com/mdn/yari/compare/v2.48.0...v2.49.0) (2024-04-18)
+
+
+### Features
+
+* **experiment:** rewrite Web/API page titles ([#10926](https://github.com/mdn/yari/issues/10926)) ([d8173cc](https://github.com/mdn/yari/commit/d8173cc190686634cd43f0a83b4f6178a133e9f5))
+
+
+### Bug Fixes
+
+* **experiment:** replace test group for Web/API page titles ([#10955](https://github.com/mdn/yari/issues/10955)) ([1dfb5b2](https://github.com/mdn/yari/commit/1dfb5b23db7e643e8ad4c7450b9d0ceacb227cbd))
+* **playground:** dispatch DOMContentLoaded event on document + bubble ([7229dd3](https://github.com/mdn/yari/commit/7229dd334ed51281816629db88b9365858c56740))
+* **playground:** dispatch readystatechange + bubble DOMContentLoaded on document ([#10946](https://github.com/mdn/yari/issues/10946)) ([7229dd3](https://github.com/mdn/yari/commit/7229dd334ed51281816629db88b9365858c56740))
+* **playground:** dispatch readystatechange event ([7229dd3](https://github.com/mdn/yari/commit/7229dd334ed51281816629db88b9365858c56740))
+* **stage-build:** provide GH_TOKEN + specify repo in trigger job ([#10932](https://github.com/mdn/yari/issues/10932)) ([d371c0a](https://github.com/mdn/yari/commit/d371c0a8b76a6c47eb8a11d59275860559232678))
+
+
+### Enhancements
+
+* **macros/PreviousMenuNext:** use the actual title of the document by default ([#10812](https://github.com/mdn/yari/issues/10812)) ([10da897](https://github.com/mdn/yari/commit/10da8978812024f0bf3d1e21db4a36e68da33d8a))
+
+
+### Miscellaneous
+
+* **deps-dev:** bump @swc/core from 1.4.14 to 1.4.15 ([#10941](https://github.com/mdn/yari/issues/10941)) ([28f775d](https://github.com/mdn/yari/commit/28f775d91a3163b446ee8855df66d8d4b56df277))
+* **deps-dev:** bump @swc/core from 1.4.15 to 1.4.16 ([#10951](https://github.com/mdn/yari/issues/10951)) ([d099746](https://github.com/mdn/yari/commit/d09974644971491627705abd5da743fc24f65faf))
+* **deps-dev:** bump mini-css-extract-plugin from 2.8.1 to 2.9.0 ([#10938](https://github.com/mdn/yari/issues/10938)) ([672e79a](https://github.com/mdn/yari/commit/672e79a6d70bc7cd2a17cbe314a6b7e3acb221e9))
+* **deps-dev:** bump sass-loader from 14.2.0 to 14.2.1 ([#10937](https://github.com/mdn/yari/issues/10937)) ([85372d5](https://github.com/mdn/yari/commit/85372d56b9bef30c379a5e3846233feef59a1962))
+* **deps:** bump @mdn/browser-compat-data from 5.5.21 to 5.5.22 ([#10939](https://github.com/mdn/yari/issues/10939)) ([c290528](https://github.com/mdn/yari/commit/c29052859667c74d5be831d56df0c42d13e0aa62))
+* **deps:** bump @webref/css from 6.12.7 to 6.12.8 ([#10949](https://github.com/mdn/yari/issues/10949)) ([3051a61](https://github.com/mdn/yari/commit/3051a613edb2a169d63cf20415e302f56028ad7a))
+* **deps:** bump inquirer from 9.2.18 to 9.2.19 ([#10940](https://github.com/mdn/yari/issues/10940)) ([b4520ff](https://github.com/mdn/yari/commit/b4520ff50ae976be365b6ca0531f4834e3451e7a))
+* **deps:** bump openai from 4.35.0 to 4.36.0 ([#10936](https://github.com/mdn/yari/issues/10936)) ([dcda615](https://github.com/mdn/yari/commit/dcda6157cb8a0722ec43079b66bcf001fe6beb92))
+* **deps:** bump openai from 4.36.0 to 4.37.1 ([#10950](https://github.com/mdn/yari/issues/10950)) ([c6212c4](https://github.com/mdn/yari/commit/c6212c4f155db69dd464e7708cdca33570b53e15))
+* **deps:** bump web-specs from 3.7.1 to 3.8.0 ([#10952](https://github.com/mdn/yari/issues/10952)) ([126088d](https://github.com/mdn/yari/commit/126088dce86f68adeabed833943cd86883899f34))
+
## [2.48.0](https://github.com/mdn/yari/compare/v2.47.0...v2.48.0) (2024-04-16)
diff --git a/build/index.ts b/build/index.ts
index 0bc3210fce02..ba4a2a08bfbe 100644
--- a/build/index.ts
+++ b/build/index.ts
@@ -44,6 +44,7 @@ import {
postProcessSmallerHeadingIDs,
} from "./utils.js";
import { getWebFeatureStatus } from "./web-features.js";
+import { rewritePageTitleForSEO } from "./seo.js";
export { default as SearchIndex } from "./search-index.js";
export { gather as gatherGitHistory } from "./git-history.js";
export { buildSPAs } from "./spas.js";
@@ -536,7 +537,8 @@ export async function buildDocument(
// a breadcrumb in the React component.
addBreadcrumbData(document.url, doc);
- doc.pageTitle = getPageTitle(doc);
+ const pageTitle = getPageTitle(doc);
+ doc.pageTitle = rewritePageTitleForSEO(doc.mdn_url, pageTitle);
// Decide whether it should be indexed (sitemaps, robots meta tag, search-index)
doc.noIndexing =
diff --git a/build/seo.ts b/build/seo.ts
new file mode 100644
index 000000000000..4cb2639eb446
--- /dev/null
+++ b/build/seo.ts
@@ -0,0 +1,526 @@
+// URLs of 500 pages randomly sampled from 4824 affected Web/API pages.
+const TEST_GROUP = new Set(
+ [
+ "SVGStyleElement/media",
+ "MutationEvent/initMutationEvent",
+ "CSSPrimitiveValue/getStringValue",
+ "RTCIceCandidateStats/candidateType",
+ "RTCIceCandidate/relatedPort",
+ "Cache/match",
+ "URLSearchParams/append",
+ "XRWebGLBinding/createEquirectLayer",
+ "Element/ariaBusy",
+ "GPUQuerySet/count",
+ "UIEvent/detail",
+ "Selection/toString",
+ "MediaTrackConstraints/frameRate",
+ "FileSystemSyncAccessHandle/truncate",
+ "StylePropertyMapReadOnly/keys",
+ "NetworkInformation/type",
+ "WebGLRenderingContext/uniform",
+ "DOMMatrixReadOnly/flipX",
+ "XMLHttpRequest/status",
+ "RTCIceTransport/getLocalCandidates",
+ "BroadcastChannel/close",
+ "GPUDevice/lost",
+ "RTCOutboundRtpStreamStats/perDscpPacketsSent",
+ "AudioListener/upZ",
+ "BackgroundFetchRegistration/id",
+ "ReadableStream/ReadableStream",
+ "Notification/body",
+ "InterventionReportBody/lineNumber",
+ "WorkerNavigator/locks",
+ "InterventionReportBody/toJSON",
+ "ElementInternals/ariaValueMax",
+ "Response/bodyUsed",
+ "HTMLMediaElement/setSinkId",
+ "GPU/getPreferredCanvasFormat",
+ "WebGL2RenderingContext/beginTransformFeedback",
+ "CSSScopeRule/start",
+ "CacheStorage/keys",
+ "DedicatedWorkerGlobalScope/postMessage",
+ "RTCDTMFSender/toneBuffer",
+ "PushSubscriptionOptions/applicationServerKey",
+ "WebTransportDatagramDuplexStream/incomingMaxAge",
+ "BatteryManager/charging",
+ "Navigator/vibrate",
+ "StylePropertyMapReadOnly/size",
+ "TextMetrics/fontBoundingBoxAscent",
+ "XRInputSourcesChangeEvent/XRInputSourcesChangeEvent",
+ "MediaDeviceInfo/deviceId",
+ "BaseAudioContext/createChannelMerger",
+ "ImageData/ImageData",
+ "URL/origin",
+ "ServiceWorkerRegistration/active",
+ "NavigationHistoryEntry/key",
+ "ContentIndex/add",
+ "Document/xmlVersion",
+ "RemotePlayback/watchAvailability",
+ "Document/documentElement",
+ "MathMLElement/style",
+ "WebGL2RenderingContext/uniformMatrix",
+ "DeprecationReportBody/lineNumber",
+ "SerialPort/forget",
+ "GPUDevice/popErrorScope",
+ "TaskController/TaskController",
+ "FileSystemEntry/isDirectory",
+ "console/timelog_static",
+ "Selection/type",
+ "XRViewerPose/views",
+ "CanvasRenderingContext2D/fontStretch",
+ "BaseAudioContext/createConvolver",
+ "Touch/radiusX",
+ "WebGL2RenderingContext/texSubImage3D",
+ "Event/srcElement",
+ "Element/ariaPosInSet",
+ "CSSUnparsedValue/entries",
+ "XRLightEstimate/primaryLightIntensity",
+ "XRSession/requestReferenceSpace",
+ "VideoFrame/allocationSize",
+ "AudioContext/createMediaStreamTrackSource",
+ "GPUQueue/onSubmittedWorkDone",
+ "ExtendableMessageEvent/lastEventId",
+ "MediaEncryptedEvent/initData",
+ "HTMLAreaElement/ping",
+ "EXT_disjoint_timer_query/getQueryObjectEXT",
+ "Worklet/addModule",
+ "Request/clone",
+ "PasswordCredential/name",
+ "Location/origin",
+ "MediaTrackConstraints/sampleSize",
+ "GPURenderPassEncoder/executeBundles",
+ "XMLHttpRequest/send",
+ "console/time_static",
+ "HTMLTableElement/frame",
+ "IDBObjectStore/getKey",
+ "TextTrackCue/id",
+ "WritableStreamDefaultController/signal",
+ "RadioNodeList/value",
+ "Element/ariaBrailleRoleDescription",
+ "NavigatorUAData/toJSON",
+ "Cache/delete",
+ "OVR_multiview2/framebufferTextureMultiviewOVR",
+ "WebGLRenderingContext/getSupportedExtensions",
+ "DedicatedWorkerGlobalScope/name",
+ "DOMPointReadOnly/y",
+ "Range/collapsed",
+ "USBDevice/controlTransferIn",
+ "console/profile_static",
+ "HTMLImageElement/decoding",
+ "Window/postMessage",
+ "HTMLVideoElement/videoWidth",
+ "TextTrack/language",
+ "Element/getElementsByClassName",
+ "AudioEncoder/isConfigSupported_static",
+ "AudioData/AudioData",
+ "CSSNumericValue/type",
+ "IDBDatabase/name",
+ "AnimationEvent/pseudoElement",
+ "BaseAudioContext/createAnalyser",
+ "CSSVariableReferenceValue/variable",
+ "PresentationConnection/binaryType",
+ "CredentialsContainer/create",
+ "ElementInternals/setValidity",
+ "PannerNode/setOrientation",
+ "DOMPointReadOnly/toJSON",
+ "SVGAnimatedString/baseVal",
+ "Document/links",
+ "GPURenderBundleEncoder/drawIndirect",
+ "CSSSkewY/ay",
+ "Window/getSelection",
+ "IDBObjectStore/clear",
+ "HTMLElement/click",
+ "HTMLTableElement/cellPadding",
+ "RTCIceCandidatePairStats/writable",
+ "XRRigidTransform/position",
+ "OffscreenCanvas/width",
+ "RTCCertificateStats/fingerprint",
+ "ChannelSplitterNode/ChannelSplitterNode",
+ "PerformanceResourceTiming/redirectEnd",
+ "NamedNodeMap/length",
+ "Path2D/Path2D",
+ "SecurityPolicyViolationEvent/originalPolicy",
+ "ServiceWorkerRegistration/navigationPreload",
+ "GPUTexture/height",
+ "ValidityState/rangeOverflow",
+ "SpeechSynthesis/getVoices",
+ "BluetoothRemoteGATTDescriptor/writeValue",
+ "PaymentRequestEvent/methodData",
+ "TaskController/setPriority",
+ "MouseEvent/screenY",
+ "XRView/eye",
+ "ExtendableCookieChangeEvent/ExtendableCookieChangeEvent",
+ "ContactAddress/recipient",
+ "Document/prepend",
+ "MediaTrackSupportedConstraints/channelCount",
+ "XRMediaBinding/createCylinderLayer",
+ "Blob/type",
+ "CustomElementRegistry/whenDefined",
+ "Navigator/getUserMedia",
+ "WebGLRenderingContext/viewport",
+ "Navigator/hid",
+ "URLPattern/password",
+ "GamepadPose/orientation",
+ "HTMLAreaElement/hash",
+ "Performance/getEntriesByName",
+ "FileReader/readAsDataURL",
+ "Location/hash",
+ "Screen/isExtended",
+ "StyleSheet/media",
+ "MIDIOutput/clear",
+ "Element/tagName",
+ "BarProp/visible",
+ "RTCInboundRtpStreamStats/qpSum",
+ "HTMLMediaElement/networkState",
+ "ElementInternals/ariaAutoComplete",
+ "ViewTimeline/ViewTimeline",
+ "WritableStreamDefaultWriter/write",
+ "ServiceWorkerContainer/ready",
+ "Window/scrollY",
+ "CustomStateSet/has",
+ "HTMLImageElement/vspace",
+ "Range/cloneRange",
+ "TransformStream/writable",
+ "SVGAnimatedEnumeration/baseVal",
+ "PositionSensorVRDevice/getImmediateState",
+ "PaymentResponse/retry",
+ "Document/createTreeWalker",
+ "XRSession/requestLightProbe",
+ "HTMLAnchorElement/username",
+ "WebGLRenderingContext/deleteShader",
+ "WebGLRenderingContext/texSubImage2D",
+ "CanvasRenderingContext2D/clearRect",
+ "Navigator/productSub",
+ "HMDVRDevice/setFieldOfView",
+ "HTMLObjectElement/useMap",
+ "WebGLRenderingContext/isRenderbuffer",
+ "Element/closest",
+ "HTMLElement/blur",
+ "GPUCommandEncoder/clearBuffer",
+ "PromiseRejectionEvent/PromiseRejectionEvent",
+ "GPUDevice/createSampler",
+ "IDBObjectStore/openKeyCursor",
+ "Window/speechSynthesis",
+ "WebGLRenderingContext/stencilMaskSeparate",
+ "Request/referrer",
+ "RTCStatsReport/get",
+ "HTMLSelectElement/namedItem",
+ "HIDDevice/sendReport",
+ "XRRay/matrix",
+ "HTMLImageElement/Image",
+ "DOMMatrixReadOnly/scale",
+ "PerformanceLongTaskTiming/attribution",
+ "SecurityPolicyViolationEvent/referrer",
+ "HTMLMediaElement/defaultPlaybackRate",
+ "PushManager/register",
+ "InterventionReportBody/columnNumber",
+ "BackgroundFetchRegistration/recordsAvailable",
+ "HTMLElement/inert",
+ "ConvolverNode/ConvolverNode",
+ "HTMLImageElement/height",
+ "ResizeObserverSize/inlineSize",
+ "Text/assignedSlot",
+ "RTCDtlsTransport/state",
+ "GeolocationCoordinates/altitudeAccuracy",
+ "WebGLRenderingContext/isContextLost",
+ "AbortSignal/throwIfAborted",
+ "CSSCounterStyleRule/negative",
+ "HTMLLabelElement/form",
+ "TaskSignal/any_static",
+ "SVGGeometryElement/getTotalLength",
+ "CSSMathNegate/CSSMathNegate",
+ "NavigatorUAData/getHighEntropyValues",
+ "CSSNumericValue/to",
+ "URLSearchParams/delete",
+ "SpeechRecognitionResult/isFinal",
+ "XRSession/interactionMode",
+ "SpeechGrammarList/addFromURI",
+ "PointerEvent/twist",
+ "XRViewport/x",
+ "Range/createContextualFragment",
+ "Navigator/locks",
+ "MessagePort/start",
+ "RTCPeerConnection/setRemoteDescription",
+ "RTCRtpTransceiver/receiver",
+ "FileSystemDirectoryEntry/getFile",
+ "Document/lastStyleSheetSet",
+ "IDBCursor/source",
+ "VREyeParameters/offset",
+ "CSSRule/parentStyleSheet",
+ "Document/childElementCount",
+ "CSSPropertyRule/syntax",
+ "VRDisplay/submitFrame",
+ "HTMLElement/title",
+ "PaymentAddress/sortingCode",
+ "RTCVideoSourceStats/id",
+ "GPURenderPassEncoder/setBindGroup",
+ "MediaKeyStatusMap/values",
+ "MediaStream/getVideoTracks",
+ "ElementInternals/ariaLevel",
+ "HTMLMediaElement/controls",
+ "WritableStream/getWriter",
+ "Selection/setBaseAndExtent",
+ "RTCIceCandidate/protocol",
+ "NodeList/values",
+ "XRWebGLLayer/fixedFoveation",
+ "UIEvent/sourceCapabilities",
+ "ShadowRoot/pointerLockElement",
+ "OrientationSensor/populateMatrix",
+ "HTMLFormElement/target",
+ "PeriodicSyncEvent/PeriodicSyncEvent",
+ "USB/requestDevice",
+ "HTMLAreaElement/relList",
+ "HIDConnectionEvent/HIDConnectionEvent",
+ "MediaStream/addTrack",
+ "SerialPort/setSignals",
+ "RTCError/errorDetail",
+ "HTMLInputElement/disabled",
+ "BackgroundFetchRegistration/downloadTotal",
+ "PushSubscriptionOptions/userVisibleOnly",
+ "VTTCue/align",
+ "URLSearchParams/sort",
+ "AbstractRange/startOffset",
+ "ImageTrackList/selectedIndex",
+ "Bluetooth/getDevices",
+ "LargestContentfulPaint/id",
+ "CSSFontPaletteValuesRule/basePalette",
+ "OverconstrainedError/constraint",
+ "ElementInternals/ariaCurrent",
+ "NDEFRecord/encoding",
+ "GPURenderBundleEncoder/insertDebugMarker",
+ "Element/clientTop",
+ "SVGMarkerElement/markerWidth",
+ "Performance/mark",
+ "RTCRemoteOutboundRtpStreamStats/ssrc",
+ "NodeList/entries",
+ "Element/clientLeft",
+ "ServiceWorkerRegistration/paymentManager",
+ "RTCCodecStats/id",
+ "TransitionEvent/TransitionEvent",
+ "RTCDataChannel/bufferedAmountLowThreshold",
+ "ShadowRoot/adoptedStyleSheets",
+ "MediaQueryList/media",
+ "ImageTrack/animated",
+ "Request/headers",
+ "PerformanceTiming/domainLookupEnd",
+ "BackgroundFetchRegistration/uploadTotal",
+ "PerformanceTiming/domComplete",
+ "ImageCapture/getPhotoCapabilities",
+ "Document/selectedStyleSheetSet",
+ "WebGLRenderingContext/blendFuncSeparate",
+ "CanvasRenderingContext2D/shadowColor",
+ "XSLTProcessor/XSLTProcessor",
+ "XRCylinderLayer/radius",
+ "RTCRtpStreamStats/pliCount",
+ "StorageEvent/newValue",
+ "GPUBuffer/unmap",
+ "RTCPeerConnection/createAnswer",
+ "XMLHttpRequest/overrideMimeType",
+ "WebGL2RenderingContext/transformFeedbackVaryings",
+ "Window/closed",
+ "AudioTrack/kind",
+ "HTMLAnchorElement/search",
+ "WebGLRenderingContext/createBuffer",
+ "WebGLRenderingContext/getTexParameter",
+ "XMLHttpRequest/setRequestHeader",
+ "MutationRecord/attributeNamespace",
+ "BaseAudioContext/createConstantSource",
+ "VREyeParameters/minimumFieldOfView",
+ "WindowControlsOverlay/getTitlebarAreaRect",
+ "SVGPointList/appendItem",
+ "AuthenticatorResponse/clientDataJSON",
+ "RTCTrackEvent/track",
+ "AudioDestinationNode/maxChannelCount",
+ "History/replaceState",
+ "PaymentRequestUpdateEvent/PaymentRequestUpdateEvent",
+ "ImageData/data",
+ "CSSRule/type",
+ "BeforeInstallPromptEvent/userChoice",
+ "IDBObjectStore/put",
+ "NavigateEvent/formData",
+ "StaticRange/collapsed",
+ "PannerNode/PannerNode",
+ "XRWebGLBinding/createCylinderLayer",
+ "FileSystemFileEntry/createWriter",
+ "Touch/Touch",
+ "IDBVersionChangeEvent/IDBVersionChangeEvent",
+ "HIDInputReportEvent/device",
+ "PerformanceResourceTiming/domainLookupStart",
+ "HTMLTableElement/border",
+ "RTCCertificateStats/timestamp",
+ "IdentityCredential/isAutoSelected",
+ "MediaStreamTrack/enabled",
+ "Range/endOffset",
+ "IDBTransaction/mode",
+ "Response/status",
+ "PaymentAddress/recipient",
+ "TouchEvent/touches",
+ "MediaStreamEvent/stream",
+ "ImageTrack/frameCount",
+ "URL/hash",
+ "TextMetrics/ideographicBaseline",
+ "FileSystemFileHandle/createWritable",
+ "Event/stopPropagation",
+ "ScreenDetailed/left",
+ "EXT_disjoint_timer_query/beginQueryEXT",
+ "NavigateEvent/userInitiated",
+ "DocumentFragment/querySelectorAll",
+ "NavigatorUAData/brands",
+ "RTCIceCandidate/tcpType",
+ "HTMLElement/togglePopover",
+ "MediaTrackConstraints/autoGainControl",
+ "ElementInternals/ariaLive",
+ "Navigator/getGamepads",
+ "DynamicsCompressorNode/attack",
+ "CharacterData/deleteData",
+ "ImageCapture/getPhotoSettings",
+ "WritableStreamDefaultWriter/abort",
+ "XRDepthInformation/rawValueToMeters",
+ "WorkerNavigator/serial",
+ "XRWebGLLayer/XRWebGLLayer",
+ "Fence/getNestedConfigs",
+ "AnalyserNode/frequencyBinCount",
+ "BaseAudioContext/state",
+ "HTMLAreaElement/origin",
+ "AudioBuffer/length",
+ "WebSocket/binaryType",
+ "SVGElement/style",
+ "Document/getElementById",
+ "ScreenOrientation/angle",
+ "FileReader/FileReader",
+ "MediaStreamAudioDestinationNode/stream",
+ "Document/lastElementChild",
+ "ReadableByteStreamController/close",
+ "TextUpdateEvent/text",
+ "CSSStyleSheet/removeRule",
+ "AudioNode/channelCount",
+ "ImageData/colorSpace",
+ "DOMMatrixReadOnly/translate",
+ "XRInputSourceArray/keys",
+ "ElementInternals/ariaAtomic",
+ "DeviceOrientationEvent/DeviceOrientationEvent",
+ "CountQueuingStrategy/size",
+ "RTCRtpSender/setStreams",
+ "BluetoothRemoteGATTCharacteristic/writeValue",
+ "SecurityPolicyViolationEvent/violatedDirective",
+ "AudioParam/linearRampToValueAtTime",
+ "HTMLButtonElement/disabled",
+ "WaveShaperNode/curve",
+ "SVGRect/The__X__property",
+ "CSSTransformValue/keys",
+ "ServiceWorkerRegistration/getNotifications",
+ "Notification/timestamp",
+ "IDBObjectStore/count",
+ "AudioParam/cancelScheduledValues",
+ "XREquirectLayer/radius",
+ "CSSUnparsedValue/CSSUnparsedValue",
+ "XSLTProcessor/getParameter",
+ "Navigator/keyboard",
+ "Metadata/modificationTime",
+ "MediaDeviceInfo/kind",
+ "NavigationHistoryEntry/sameDocument",
+ "ViewTimeline/endOffset",
+ "PerformanceNavigationTiming/toJSON",
+ "XRProjectionLayer/fixedFoveation",
+ "WebGLRenderingContext/compressedTexSubImage2D",
+ "RTCPeerConnection/getIdentityAssertion",
+ "Navigation/traverseTo",
+ "InputEvent/InputEvent",
+ "Storage/length",
+ "ReadableStreamBYOBReader/closed",
+ "VRFrameData/timestamp",
+ "WheelEvent/WheelEvent",
+ "Window/window",
+ "VRDisplayEvent/VRDisplayEvent",
+ "RTCRtpStreamStats/qpSum",
+ "TrustedTypePolicy/name",
+ "StylePropertyMap/set",
+ "ReadableStreamDefaultController/close",
+ "RTCSessionDescription/RTCSessionDescription",
+ "URL/toString",
+ "OffscreenCanvas/convertToBlob",
+ "HTMLSlotElement/assign",
+ "MediaTrackSupportedConstraints/displaySurface",
+ "GPUAdapter/features",
+ "HTMLFormElement/encoding",
+ "PerformanceMeasure/detail",
+ "OES_vertex_array_object/deleteVertexArrayOES",
+ "Document/fullscreenEnabled",
+ "TextUpdateEvent/TextUpdateEvent",
+ "StorageEvent/storageArea",
+ "PerformanceServerTiming/name",
+ "PerformanceNavigation/type",
+ "InterventionReportBody/id",
+ "Window/statusbar",
+ "Document/anchors",
+ "Navigator/presentation",
+ "Bluetooth/getAvailability",
+ "USBDevice/selectConfiguration",
+ "FileSystemDirectoryHandle/entries",
+ "Element/ariaAtomic",
+ "IDBIndex/openKeyCursor",
+ "BaseAudioContext/createChannelSplitter",
+ "VideoColorSpace/transfer",
+ "MediaTrackConstraints/displaySurface",
+ "CSSPropertyRule/initialvalue",
+ "KeyframeEffect/setKeyframes",
+ "RTCStatsReport/forEach",
+ "SourceBuffer/changeType",
+ "GPURenderPassEncoder/end",
+ "RTCRtpScriptTransformer/writable",
+ "CSSNamespaceRule/prefix",
+ "ScreenDetailed/label",
+ "PaymentRequest/shippingType",
+ "MediaTrackSettings/logicalSurface",
+ "HTMLTemplateElement/content",
+ "IDBCursor/continuePrimaryKey",
+ "window/getDefaultComputedStyle",
+ "FileSystemWritableFileStream/seek",
+ "CanvasRenderingContext2D/shadowBlur",
+ "GPUCommandEncoder/copyTextureToTexture",
+ "GPURenderBundleEncoder/setPipeline",
+ "FileSystem/name",
+ "USBDevice/opened",
+ "IDBCursor/key",
+ "HTMLFencedFrameElement/height",
+ "PerformanceObserver/PerformanceObserver",
+ "Blob/stream",
+ "MediaTrackConstraints/volume",
+ "LaunchQueue/setConsumer",
+ "HTMLInputElement/stepDown",
+ "CSSStyleDeclaration/getPropertyCSSValue",
+ "BaseAudioContext/createPeriodicWave",
+ "GamepadEvent/gamepad",
+ "MouseEvent/WEBKIT_FORCE_AT_FORCE_MOUSE_DOWN_static",
+ "SpeechSynthesisEvent/charIndex",
+ "MediaTrackSupportedConstraints/volume",
+ "BluetoothRemoteGATTCharacteristic/stopNotifications",
+ "Element/prepend",
+ "FormData/FormData",
+ "Highlight/priority",
+ "NavigateEvent/info",
+ "HTMLAudioElement/Audio",
+ "MediaKeySession/generateRequest",
+ ].map((slugSuffix) => `/en-US/docs/Web/API/${slugSuffix}`.toLowerCase())
+);
+
+export function rewritePageTitleForSEO(
+ mdn_url: string,
+ s: string | null
+): string | null {
+ if (
+ typeof s !== "string" ||
+ typeof mdn_url !== "string" ||
+ !TEST_GROUP.has(mdn_url.toLowerCase())
+ ) {
+ return s;
+ }
+
+ return (
+ s
+ // "AudioBuffer: sampleRate property" -> "AudioBuffer.sampleRate property"
+ .replace(/^(.*): (.*?) (static )?(method|property)/, "$1.$2 $3$4")
+ // "AudioBuffer: AudioBuffer() constructor" -> "AudioBuffer() constructor"
+ .replace(/^(.*): (\1\(\)) constructor/, "$2 constructor") ?? null
+ );
+}
diff --git a/client/public/runner.html b/client/public/runner.html
index f3cb4e839b3b..a6b75d798221 100644
--- a/client/public/runner.html
+++ b/client/public/runner.html
@@ -121,8 +121,12 @@
script.textContent = state.js;
document.body.appendChild(script);
- dispatchEvent(new Event("DOMContentLoaded"));
- dispatchEvent(new Event("load"));
+ document.dispatchEvent(
+ new Event("DOMContentLoaded", { bubbles: true })
+ );
+ document.dispatchEvent(new Event("readystatechange"));
+ window.dispatchEvent(new Event("load"));
+
initialized = true;
}
window.addEventListener("message", (event) => {
diff --git a/client/src/flaws/index.scss b/client/src/flaws/index.scss
index ee4bc40fe8a8..c75394775bf9 100644
--- a/client/src/flaws/index.scss
+++ b/client/src/flaws/index.scss
@@ -3,10 +3,6 @@
background-color: var(--background-warning);
}
- h3 {
- margin-top: 0;
- }
-
h3 span.page {
color: var(--text-inactive);
}
@@ -66,7 +62,6 @@
gap: 20px;
grid-template-columns: 300px 1fr;
margin: auto;
- width: calc(100% - 40px);
.filters {
h4 {
diff --git a/client/src/translations/dashboard/index.tsx b/client/src/translations/dashboard/index.tsx
index 953858a8c9a7..781412785c1c 100644
--- a/client/src/translations/dashboard/index.tsx
+++ b/client/src/translations/dashboard/index.tsx
@@ -8,6 +8,7 @@ import {
import useSWR from "swr";
import { MainContentContainer } from "../../ui/atoms/page-content";
+import { Icon } from "../../ui/atoms/icon";
import { useLocale } from "../../hooks";
interface Data {
@@ -193,7 +194,7 @@ export function TranslationDashboard() {
)}
{error &&