@mdn/fred 2.5.0 → 2.6.0
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.
- package/CHANGELOG.md +21 -0
- package/components/a11y-menu/server.js +2 -2
- package/components/breadcrumbs/server.js +6 -1
- package/components/collection-save-button/element.js +15 -0
- package/components/color-theme/element.js +17 -1
- package/components/compat-table/element.js +10 -1
- package/components/content-section/server.css +5 -0
- package/components/curriculum-landing/server.js +4 -1
- package/components/dropdown/element.js +12 -1
- package/components/featured-articles/server.js +10 -3
- package/components/footer/server.js +6 -1
- package/components/generic-about/server.js +1 -0
- package/components/generic-toc/server.js +6 -1
- package/components/language-always-redirect-button/element.js +2 -0
- package/components/language-switcher/element.js +5 -0
- package/components/latest-news/server.js +10 -3
- package/components/login-button/element.js +1 -1
- package/components/menu/server.js +3 -1
- package/components/observatory-form/element.js +3 -0
- package/components/observatory-results/element.js +6 -1
- package/components/observatory-results/rating.js +6 -1
- package/components/placement-top/element.js +16 -4
- package/components/playground/element.js +17 -4
- package/components/recent-contributions/server.js +4 -1
- package/components/reference-toc/server.js +5 -1
- package/components/scrim-inline/element.js +13 -1
- package/components/sidebar-filter/element.js +11 -0
- package/components/translation-banner/server.js +4 -1
- package/components/user-menu/element.js +1 -0
- package/components/viewed-controller/viewed-controller.js +15 -59
- package/components/viewed-controller/viewed-observer.js +79 -0
- package/hooks/glean-init.js +49 -6
- package/l10n/locales/zh-CN.ftl +317 -1
- package/out/service-worker.js +1 -1
- package/out/static/client/{2173.c74593faf7e14cbc.js → 2173.a662dd40657c8426.js} +2 -2
- package/out/static/client/{2173.c74593faf7e14cbc.js.map → 2173.a662dd40657c8426.js.map} +1 -1
- package/out/static/client/{2868.b09544148fff25a1.js → 2868.03299f12d5927ed2.js} +2 -2
- package/out/static/client/{2868.b09544148fff25a1.js.map → 2868.03299f12d5927ed2.js.map} +1 -1
- package/out/static/client/{291.91650ffed3a60424.js → 291.c90e43b3c10a9a1f.js} +27 -16
- package/out/static/client/291.c90e43b3c10a9a1f.js.map +1 -0
- package/out/static/client/{3259.ac8a5539251c647a.js → 3259.c4b809cd884ad515.js} +29 -24
- package/out/static/client/3259.c4b809cd884ad515.js.map +1 -0
- package/out/static/client/{3775.c64e09b2fc1d9b21.js → 3775.cf93e968f166d25a.js} +2 -1
- package/out/static/client/{3775.c64e09b2fc1d9b21.js.map → 3775.cf93e968f166d25a.js.map} +1 -1
- package/out/static/client/{4060.9a7bb116e3112c13.js → 4060.a23acd149888555c.js} +2 -2
- package/out/static/client/{4060.9a7bb116e3112c13.js.map → 4060.a23acd149888555c.js.map} +1 -1
- package/out/static/client/4249.19f86ee6b57a13b0.js +2 -0
- package/out/static/client/4249.19f86ee6b57a13b0.js.map +1 -0
- package/out/static/client/{4759.8981c79d33088d8f.js → 4759.5852733a45132491.js} +2 -2
- package/out/static/client/{4759.8981c79d33088d8f.js.map → 4759.5852733a45132491.js.map} +1 -1
- package/out/static/client/{4920.033c028023478df5.js → 4920.929203da4613c89a.js} +3 -2
- package/out/static/client/4920.929203da4613c89a.js.map +1 -0
- package/out/static/client/{5183.6c532a6e7b0d0bbb.js → 5183.48a6059ffe2931f0.js} +12 -12
- package/out/static/client/5183.48a6059ffe2931f0.js.map +1 -0
- package/out/static/client/{544.1ed814181b24bcc8.js → 544.2ccdc928c5292631.js} +3 -3
- package/out/static/client/544.2ccdc928c5292631.js.map +1 -0
- package/out/static/client/{5667.332b2c6c10792ad6.js → 5667.edd77c81ec38a7e2.js} +5 -4
- package/out/static/client/5667.edd77c81ec38a7e2.js.map +1 -0
- package/out/static/client/5685.d30658d4c274ac13.js +4 -0
- package/out/static/client/5685.d30658d4c274ac13.js.map +1 -0
- package/out/static/client/{6002.60280d36f6ea71ff.js → 6002.bb83fdc66501b6e4.js} +27 -27
- package/out/static/client/6002.bb83fdc66501b6e4.js.map +1 -0
- package/out/static/client/{6067.a60fb66b75579c98.js → 6067.169a9ec1f47871ae.js} +3 -3
- package/out/static/client/6067.169a9ec1f47871ae.js.map +1 -0
- package/out/static/client/{8364.13d1d6770264c970.js → 8364.f7862244a6ff6a1b.js} +3 -3
- package/out/static/client/8364.f7862244a6ff6a1b.js.map +1 -0
- package/out/static/client/{9204.f8aa5d9f8a79f3d4.js → 9204.f45896951abfbd28.js} +3 -3
- package/out/static/client/{9204.f8aa5d9f8a79f3d4.js.map → 9204.f45896951abfbd28.js.map} +1 -1
- package/out/static/client/9324.9646c5839948c8ff.js +27 -0
- package/out/static/client/{9324.61778c81f15bcebc.js.map → 9324.9646c5839948c8ff.js.map} +1 -1
- package/out/static/client/9456.a17794342ff9086a.js +319 -0
- package/out/static/client/9456.a17794342ff9086a.js.map +1 -0
- package/out/static/client/index.c41c45d10cf2b50b.js +221 -0
- package/out/static/client/index.c41c45d10cf2b50b.js.map +1 -0
- package/out/static/client/{runtime.5a92d4f860d6d798.js → runtime.796d2e8ab20fb93f.js} +2 -2
- package/out/static/client/{runtime.5a92d4f860d6d798.js.map → runtime.796d2e8ab20fb93f.js.map} +1 -1
- package/out/static/client/stats.json +134 -134
- package/out/static/client/{styles-content-section.049c2352791fac9b.css → styles-content-section.cd5635d274b730e9.css} +2 -2
- package/out/static/client/{styles-content-section.049c2352791fac9b.css.map → styles-content-section.cd5635d274b730e9.css.map} +1 -1
- package/out/static/client/{styles-global.64aa0c760d2688b4.js → styles-global.2a17ab4cc47bca1f.js} +1 -1
- package/out/static/client/styles-global.79b14873ea7ab386.css +2 -0
- package/out/static/client/{styles-global.274bf4a7ba3e88ae.css.map → styles-global.79b14873ea7ab386.css.map} +1 -1
- package/out/static/ssr/9456.js +317 -1
- package/out/static/ssr/9456.js.map +1 -1
- package/out/static/ssr/index.js +209 -145
- package/out/static/ssr/index.js.map +1 -1
- package/out/static/ssr/stats.json +4 -4
- package/package.json +6 -6
- package/out/static/client/291.91650ffed3a60424.js.map +0 -1
- package/out/static/client/3259.ac8a5539251c647a.js.map +0 -1
- package/out/static/client/4920.033c028023478df5.js.map +0 -1
- package/out/static/client/5183.6c532a6e7b0d0bbb.js.map +0 -1
- package/out/static/client/544.1ed814181b24bcc8.js.map +0 -1
- package/out/static/client/5649.00f25ce181894101.js +0 -2
- package/out/static/client/5649.00f25ce181894101.js.map +0 -1
- package/out/static/client/5667.332b2c6c10792ad6.js.map +0 -1
- package/out/static/client/5685.46c8d178d072b8ac.js +0 -4
- package/out/static/client/5685.46c8d178d072b8ac.js.map +0 -1
- package/out/static/client/6002.60280d36f6ea71ff.js.map +0 -1
- package/out/static/client/6067.a60fb66b75579c98.js.map +0 -1
- package/out/static/client/8364.13d1d6770264c970.js.map +0 -1
- package/out/static/client/9324.61778c81f15bcebc.js +0 -26
- package/out/static/client/9456.dd8c12ddf52e2a7d.js +0 -3
- package/out/static/client/9456.dd8c12ddf52e2a7d.js.map +0 -1
- package/out/static/client/index.ae68bec0e2489b62.js +0 -221
- package/out/static/client/index.ae68bec0e2489b62.js.map +0 -1
- package/out/static/client/styles-global.274bf4a7ba3e88ae.css +0 -2
- /package/out/static/client/{291.91650ffed3a60424.js.LICENSE.txt → 291.c90e43b3c10a9a1f.js.LICENSE.txt} +0 -0
- /package/out/static/client/{5183.6c532a6e7b0d0bbb.js.LICENSE.txt → 5183.48a6059ffe2931f0.js.LICENSE.txt} +0 -0
- /package/out/static/client/{6067.a60fb66b75579c98.js.LICENSE.txt → 6067.169a9ec1f47871ae.js.LICENSE.txt} +0 -0
- /package/out/static/client/{8364.13d1d6770264c970.js.LICENSE.txt → 8364.f7862244a6ff6a1b.js.LICENSE.txt} +0 -0
- /package/out/static/client/{index.ae68bec0e2489b62.js.LICENSE.txt → index.c41c45d10cf2b50b.js.LICENSE.txt} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.6.0](https://github.com/mdn/fred/compare/v2.5.0...v2.6.0) (2026-04-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **glean:** port missing measurements ([#1279](https://github.com/mdn/fred/issues/1279)) ([bdbc1a1](https://github.com/mdn/fred/commit/bdbc1a166cbd4fd2dd01ce898b0f5ff7837599d9))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **content-section:** add iframe styling ([#1414](https://github.com/mdn/fred/issues/1414)) ([2696dbc](https://github.com/mdn/fred/commit/2696dbc9ad769855ef9c3356a54ef06ebdcd132c))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Miscellaneous
|
|
17
|
+
|
|
18
|
+
* **deps-dev:** bump @mdn/browser-compat-data from 7.3.12 to 7.3.13 ([#1517](https://github.com/mdn/fred/issues/1517)) ([6dbfba4](https://github.com/mdn/fred/commit/6dbfba4c396c0490f753c7a0cbc8e29f267adacb))
|
|
19
|
+
* **deps-dev:** bump postcss from 8.5.10 to 8.5.12 in the npm-dev group ([#1516](https://github.com/mdn/fred/issues/1516)) ([b605a17](https://github.com/mdn/fred/commit/b605a170bb1c003c728ecee9695197add9e07957))
|
|
20
|
+
* **deps-dev:** bump the npm-dev group with 2 updates ([#1519](https://github.com/mdn/fred/issues/1519)) ([e1f4d25](https://github.com/mdn/fred/commit/e1f4d258df237b192d391e337b72e5026ed022d0))
|
|
21
|
+
* **deps:** bump @mdn/rari from 0.2.20 to 0.2.21 ([#1525](https://github.com/mdn/fred/issues/1525)) ([63a0803](https://github.com/mdn/fred/commit/63a08039823627b6816469f7798ed54941b33a30))
|
|
22
|
+
* **I10n:** add Simplified Chinese translation ([#1510](https://github.com/mdn/fred/issues/1510)) ([ae1bf08](https://github.com/mdn/fred/commit/ae1bf083d88e3579d99e3587b687245ce26a8107))
|
|
23
|
+
|
|
3
24
|
## [2.5.0](https://github.com/mdn/fred/compare/v2.4.3...v2.5.0) (2026-04-23)
|
|
4
25
|
|
|
5
26
|
|
|
@@ -9,14 +9,14 @@ export class A11yMenu extends ServerComponent {
|
|
|
9
9
|
render(context) {
|
|
10
10
|
return html`<ul class="a11y-menu">
|
|
11
11
|
<li>
|
|
12
|
-
<a href="#content"
|
|
12
|
+
<a href="#content" data-glean-id="a11y_menu: click #content"
|
|
13
13
|
>${context.l10n(
|
|
14
14
|
"a11y-menu-skip-to-main-content",
|
|
15
15
|
)`Skip to main content`}</a
|
|
16
16
|
>
|
|
17
17
|
</li>
|
|
18
18
|
<li>
|
|
19
|
-
<a href="#search"
|
|
19
|
+
<a href="#search" data-glean-id="a11y_menu: click #search"
|
|
20
20
|
>${context.l10n("a11y-menu-skip-to-search")`Skip to search`}</a
|
|
21
21
|
>
|
|
22
22
|
</li>
|
|
@@ -18,6 +18,7 @@ export class Breadcrumbs extends ServerComponent {
|
|
|
18
18
|
return nothing;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
const total = parents.length;
|
|
21
22
|
return html`
|
|
22
23
|
<ol
|
|
23
24
|
class="breadcrumbs"
|
|
@@ -27,7 +28,11 @@ export class Breadcrumbs extends ServerComponent {
|
|
|
27
28
|
${parents.map(
|
|
28
29
|
({ uri, title }, index) => html`
|
|
29
30
|
<li property="itemListElement" typeof="ListItem">
|
|
30
|
-
<a
|
|
31
|
+
<a
|
|
32
|
+
href=${uri}
|
|
33
|
+
property="item"
|
|
34
|
+
typeof="WebPage"
|
|
35
|
+
data-glean-id="breadcrumb_click: ${total - index}/${total}"
|
|
31
36
|
><span property="name">${title}</span></a
|
|
32
37
|
>
|
|
33
38
|
<meta property="position" content=${index + 1} />
|
|
@@ -2,6 +2,7 @@ import { Task } from "@lit/task";
|
|
|
2
2
|
import { LitElement, html, nothing } from "lit";
|
|
3
3
|
|
|
4
4
|
import { L10nMixin } from "../../l10n/mixin.js";
|
|
5
|
+
import { gleanClick } from "../../utils/glean.js";
|
|
5
6
|
import { globalUser } from "../user/context.js";
|
|
6
7
|
|
|
7
8
|
import styles from "./element.css?lit";
|
|
@@ -89,16 +90,26 @@ export class MDNCollectionSaveButton extends L10nMixin(LitElement) {
|
|
|
89
90
|
});
|
|
90
91
|
|
|
91
92
|
_open() {
|
|
93
|
+
this._selectFocusEventTriggered = false;
|
|
94
|
+
gleanClick("article_actions_collections_opened");
|
|
92
95
|
this._bookmarks.run();
|
|
93
96
|
this._collections.run();
|
|
94
97
|
this.shadowRoot?.querySelector("mdn-modal")?.showModal();
|
|
95
98
|
}
|
|
96
99
|
|
|
100
|
+
_selectOpen() {
|
|
101
|
+
if (!this._selectFocusEventTriggered) {
|
|
102
|
+
gleanClick("article_actions_collection_select_opened");
|
|
103
|
+
this._selectFocusEventTriggered = true;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
97
107
|
/** @param {Event} event */
|
|
98
108
|
_selectChange({ target }) {
|
|
99
109
|
if (target instanceof HTMLSelectElement) {
|
|
100
110
|
const { value } = target;
|
|
101
111
|
if (value === ADD_VALUE) {
|
|
112
|
+
gleanClick("article_actions_new_collection");
|
|
102
113
|
this.shadowRoot?.querySelector("mdn-modal")?.close();
|
|
103
114
|
open("/en-US/plus/collections");
|
|
104
115
|
} else {
|
|
@@ -149,6 +160,9 @@ export class MDNCollectionSaveButton extends L10nMixin(LitElement) {
|
|
|
149
160
|
this._lastAction = "save";
|
|
150
161
|
|
|
151
162
|
const url = `/api/v2/collections/${collectionId}/items/${item ? `${item.id}/` : ""}`;
|
|
163
|
+
|
|
164
|
+
gleanClick("new_collection_modal_submit_article_actions");
|
|
165
|
+
|
|
152
166
|
const res = await fetch(url, {
|
|
153
167
|
body: JSON.stringify({
|
|
154
168
|
url: this.docUrl,
|
|
@@ -229,6 +243,7 @@ export class MDNCollectionSaveButton extends L10nMixin(LitElement) {
|
|
|
229
243
|
)`Collection:`}
|
|
230
244
|
<select
|
|
231
245
|
.value=${this._item?.collection_id}
|
|
246
|
+
@focus=${this._selectOpen}
|
|
232
247
|
@change=${this._selectChange}
|
|
233
248
|
>
|
|
234
249
|
${collections.map(
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LitElement, html } from "lit";
|
|
2
2
|
|
|
3
3
|
import { L10nMixin } from "../../l10n/mixin.js";
|
|
4
|
+
import { gleanClick } from "../../utils/glean.js";
|
|
4
5
|
|
|
5
6
|
import styles from "./element.css?lit";
|
|
6
7
|
|
|
@@ -17,6 +18,7 @@ export class MDNColorTheme extends L10nMixin(LitElement) {
|
|
|
17
18
|
super();
|
|
18
19
|
/** @type {import("./types.js").ColorScheme} */
|
|
19
20
|
this._mode = "light dark";
|
|
21
|
+
this._closingFromSelect = false;
|
|
20
22
|
this._options = Object.entries({
|
|
21
23
|
"light dark": this.l10n("theme-default")`OS default`,
|
|
22
24
|
light: this.l10n("color-theme-light")`Light`,
|
|
@@ -30,6 +32,8 @@ export class MDNColorTheme extends L10nMixin(LitElement) {
|
|
|
30
32
|
const mode = target.dataset.mode;
|
|
31
33
|
if (mode === "light dark" || mode === "light" || mode === "dark") {
|
|
32
34
|
this._mode = mode;
|
|
35
|
+
const gleanMode = mode === "light dark" ? "os-default" : mode;
|
|
36
|
+
gleanClick(`theme_switcher: switch -> ${gleanMode}`);
|
|
33
37
|
try {
|
|
34
38
|
localStorage.setItem("theme", mode);
|
|
35
39
|
} catch (error) {
|
|
@@ -37,12 +41,24 @@ export class MDNColorTheme extends L10nMixin(LitElement) {
|
|
|
37
41
|
}
|
|
38
42
|
const dropdown = this.shadowRoot?.querySelector("mdn-dropdown");
|
|
39
43
|
if (dropdown) {
|
|
44
|
+
this._closingFromSelect = true;
|
|
40
45
|
dropdown.open = false;
|
|
41
46
|
}
|
|
42
47
|
}
|
|
43
48
|
}
|
|
44
49
|
}
|
|
45
50
|
|
|
51
|
+
/** @param {Event} event */
|
|
52
|
+
_onDropdownToggle({ target }) {
|
|
53
|
+
if (target instanceof HTMLElement && "open" in target) {
|
|
54
|
+
if (!target.open && this._closingFromSelect) {
|
|
55
|
+
this._closingFromSelect = false;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
gleanClick(`theme_switcher: ${target.open ? "open" : "close"}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
46
62
|
/**
|
|
47
63
|
* @param {import("lit").PropertyValues<this>} changedProperties
|
|
48
64
|
*/
|
|
@@ -61,7 +77,7 @@ export class MDNColorTheme extends L10nMixin(LitElement) {
|
|
|
61
77
|
|
|
62
78
|
render() {
|
|
63
79
|
return html`<div class="color-theme">
|
|
64
|
-
<mdn-dropdown>
|
|
80
|
+
<mdn-dropdown @toggle=${this._onDropdownToggle}>
|
|
65
81
|
<button
|
|
66
82
|
part="button"
|
|
67
83
|
slot="button"
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { LitElement, html, nothing } from "lit";
|
|
2
2
|
import { ifDefined } from "lit/directives/if-defined.js";
|
|
3
|
+
import { createRef, ref } from "lit/directives/ref.js";
|
|
3
4
|
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
4
5
|
|
|
5
6
|
import { L10nMixin } from "../../l10n/mixin.js";
|
|
7
|
+
import { gleanClick } from "../../utils/glean.js";
|
|
8
|
+
import { ViewedController } from "../viewed-controller/viewed-controller.js";
|
|
6
9
|
|
|
7
10
|
import { DEFAULT_LOCALE, ISSUE_METADATA_TEMPLATE } from "./constants.js";
|
|
8
11
|
import styles from "./element.css?lit";
|
|
@@ -73,6 +76,9 @@ export class MDNCompatTable extends L10nMixin(LitElement) {
|
|
|
73
76
|
|
|
74
77
|
static styles = styles;
|
|
75
78
|
|
|
79
|
+
/** @type {import("lit/directives/ref.js").Ref<HTMLElement>} */
|
|
80
|
+
_ref = createRef();
|
|
81
|
+
|
|
76
82
|
constructor() {
|
|
77
83
|
super();
|
|
78
84
|
this.query = "";
|
|
@@ -88,6 +94,9 @@ export class MDNCompatTable extends L10nMixin(LitElement) {
|
|
|
88
94
|
this._browsers = [];
|
|
89
95
|
/** @type {string|undefined} */
|
|
90
96
|
this._showTimelineId = undefined;
|
|
97
|
+
new ViewedController(this, this._ref, () => {
|
|
98
|
+
gleanClick(`bcd: view -> ${this.query}`);
|
|
99
|
+
});
|
|
91
100
|
}
|
|
92
101
|
|
|
93
102
|
get _breadcrumbs() {
|
|
@@ -255,7 +264,7 @@ export class MDNCompatTable extends L10nMixin(LitElement) {
|
|
|
255
264
|
}
|
|
256
265
|
|
|
257
266
|
_renderTable() {
|
|
258
|
-
return html`<figure class="table-container">
|
|
267
|
+
return html`<figure ${ref(this._ref)} class="table-container">
|
|
259
268
|
<figure class="table-container-inner">
|
|
260
269
|
${this._renderIssueLink()}
|
|
261
270
|
<table
|
|
@@ -257,7 +257,10 @@ export class CurriculumLanding extends ServerComponent {
|
|
|
257
257
|
const bannerLight = partnerBannerLight;
|
|
258
258
|
|
|
259
259
|
return html`
|
|
260
|
-
<section
|
|
260
|
+
<section
|
|
261
|
+
class="curriculum-partner-banner-container"
|
|
262
|
+
data-glean-view="curriculum: partner banner view"
|
|
263
|
+
>
|
|
261
264
|
<div class="partner-banner">
|
|
262
265
|
<section>
|
|
263
266
|
<h2>Learn the curriculum with Scrimba and become job ready</h2>
|
|
@@ -96,8 +96,19 @@ export class MDNDropdown extends LitElement {
|
|
|
96
96
|
`;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
/**
|
|
100
|
+
* @param {import("lit").PropertyValues<this>} changedProperties
|
|
101
|
+
*/
|
|
102
|
+
updated(changedProperties) {
|
|
100
103
|
this._setAriaAttributes();
|
|
104
|
+
if (
|
|
105
|
+
changedProperties.has("open") &&
|
|
106
|
+
changedProperties.get("open") !== undefined
|
|
107
|
+
) {
|
|
108
|
+
this.dispatchEvent(
|
|
109
|
+
new Event("toggle", { bubbles: true, composed: true }),
|
|
110
|
+
);
|
|
111
|
+
}
|
|
101
112
|
}
|
|
102
113
|
|
|
103
114
|
firstUpdated() {
|
|
@@ -10,16 +10,23 @@ export class FeaturedArticles extends ServerComponent {
|
|
|
10
10
|
render(articles) {
|
|
11
11
|
return html`<ul class="featured-articles">
|
|
12
12
|
${articles.map(
|
|
13
|
-
(article) =>
|
|
13
|
+
(article, index) =>
|
|
14
14
|
html`<li>
|
|
15
15
|
<article class="featured-articles__article">
|
|
16
16
|
${article.tag
|
|
17
|
-
? html`<a
|
|
17
|
+
? html`<a
|
|
18
|
+
class="featured-articles__tag"
|
|
19
|
+
href=${article.tag.uri}
|
|
20
|
+
data-glean-id=${`homepage: article_tag ${index + 1} -> ${article.tag.uri}`}
|
|
18
21
|
>${article.tag.title}</a
|
|
19
22
|
>`
|
|
20
23
|
: nothing}
|
|
21
24
|
<h3 class="featured-articles__title">
|
|
22
|
-
<a
|
|
25
|
+
<a
|
|
26
|
+
href=${article.mdn_url}
|
|
27
|
+
data-glean-id=${`homepage: article ${index + 1} -> ${article.mdn_url}`}
|
|
28
|
+
>${article.title}</a
|
|
29
|
+
>
|
|
23
30
|
</h3>
|
|
24
31
|
<p class="featured-articles__summary">${article.summary}</p>
|
|
25
32
|
</article>
|
|
@@ -186,6 +186,7 @@ export class Footer extends ServerComponent {
|
|
|
186
186
|
rel="noopener"
|
|
187
187
|
aria-label=${item.ariaLabel}
|
|
188
188
|
data-icon=${item.icon}
|
|
189
|
+
data-glean-id=${`footer: social -> ${item.icon}`}
|
|
189
190
|
></a>
|
|
190
191
|
</li>
|
|
191
192
|
`,
|
|
@@ -206,6 +207,7 @@ export class Footer extends ServerComponent {
|
|
|
206
207
|
class=${link.external ? "external" : ""}
|
|
207
208
|
target=${link.external ? "_blank" : undefined}
|
|
208
209
|
rel=${link.external ? "noopener" : undefined}
|
|
210
|
+
data-glean-id=${`footer: link -> ${link.href}`}
|
|
209
211
|
>
|
|
210
212
|
${link.text}
|
|
211
213
|
</a>
|
|
@@ -230,7 +232,10 @@ export class Footer extends ServerComponent {
|
|
|
230
232
|
${mozillaLinks(context).map(
|
|
231
233
|
(item) => html`
|
|
232
234
|
<li>
|
|
233
|
-
<a
|
|
235
|
+
<a
|
|
236
|
+
href=${item.href}
|
|
237
|
+
class=${item.external ? "external" : ""}
|
|
238
|
+
data-glean-id=${`footer: mozilla -> ${item.href}`}
|
|
234
239
|
>${item.text}</a
|
|
235
240
|
>
|
|
236
241
|
</li>
|
|
@@ -25,7 +25,12 @@ export class GenericToc extends ServerComponent {
|
|
|
25
25
|
${context.hyData.toc.map(
|
|
26
26
|
({ id, text }) =>
|
|
27
27
|
html`<li class="generic-toc__item">
|
|
28
|
-
<a
|
|
28
|
+
<a
|
|
29
|
+
class="generic-toc__link"
|
|
30
|
+
href="#${id}"
|
|
31
|
+
data-glean-id="toc_click: #${id}"
|
|
32
|
+
>${text}</a
|
|
33
|
+
>
|
|
29
34
|
</li>`,
|
|
30
35
|
)}
|
|
31
36
|
</ul>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { LitElement, html } from "lit";
|
|
2
2
|
|
|
3
|
+
import { gleanClick } from "../../utils/glean.js";
|
|
3
4
|
import { setPreferredLocale } from "../preferred-locale/utils.js";
|
|
4
5
|
|
|
5
6
|
export class MDNLanguageAlwaysRedirectButton extends LitElement {
|
|
@@ -15,6 +16,7 @@ export class MDNLanguageAlwaysRedirectButton extends LitElement {
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
_handleClick() {
|
|
19
|
+
gleanClick(`language: ${this.locale} -> ${this.to} (always)`);
|
|
18
20
|
setPreferredLocale(this.to);
|
|
19
21
|
const url = document.location.pathname.replace(
|
|
20
22
|
`/${this.locale}/`,
|
|
@@ -2,6 +2,7 @@ import { Task } from "@lit/task";
|
|
|
2
2
|
import { LitElement, html, nothing } from "lit";
|
|
3
3
|
|
|
4
4
|
import { L10nMixin } from "../../l10n/mixin.js";
|
|
5
|
+
import { gleanClick } from "../../utils/glean.js";
|
|
5
6
|
|
|
6
7
|
import infoIcon from "../icon/info.svg?lit";
|
|
7
8
|
import { getEnglishDoc } from "../not-found/utils.js";
|
|
@@ -63,12 +64,15 @@ export class MDNLanguageSwitcher extends L10nMixin(LitElement) {
|
|
|
63
64
|
|
|
64
65
|
_togglePreferredLocale() {
|
|
65
66
|
if (this.notFound) return;
|
|
67
|
+
const oldValue = this._preferredLocale ?? "0";
|
|
66
68
|
if (this._isLocalePreferred) {
|
|
67
69
|
resetPreferredLocale();
|
|
68
70
|
this._preferredLocale = undefined;
|
|
71
|
+
gleanClick(`language_remember: ${oldValue} -> 0`);
|
|
69
72
|
} else {
|
|
70
73
|
setPreferredLocale(this.locale);
|
|
71
74
|
this._preferredLocale = this.locale;
|
|
75
|
+
gleanClick(`language_remember: ${oldValue} -> ${this.locale}`);
|
|
72
76
|
}
|
|
73
77
|
}
|
|
74
78
|
|
|
@@ -160,6 +164,7 @@ export class MDNLanguageSwitcher extends L10nMixin(LitElement) {
|
|
|
160
164
|
`/${notFound ? "en-US" : locale}/`,
|
|
161
165
|
`/${translation.locale}/`,
|
|
162
166
|
)}
|
|
167
|
+
data-glean-id=${`language: ${locale} -> ${translation.locale}`}
|
|
163
168
|
>${translation.native}</a
|
|
164
169
|
>
|
|
165
170
|
</li>
|
|
@@ -14,16 +14,23 @@ export class LatestNews extends ServerComponent {
|
|
|
14
14
|
|
|
15
15
|
return html`<ul class="latest-news">
|
|
16
16
|
${items.map(
|
|
17
|
-
(item) =>
|
|
17
|
+
(item, index) =>
|
|
18
18
|
html`<li>
|
|
19
19
|
<article class="latest-news__item">
|
|
20
20
|
${item.source
|
|
21
|
-
? html`<a
|
|
21
|
+
? html`<a
|
|
22
|
+
class="latest-news__source"
|
|
23
|
+
href=${item.source.url}
|
|
24
|
+
data-glean-id=${`homepage: news_source ${index + 1} -> ${item.source.url}`}
|
|
22
25
|
>${item.source.name}</a
|
|
23
26
|
>`
|
|
24
27
|
: nothing}
|
|
25
28
|
<h3 class="latest-news__title">
|
|
26
|
-
<a
|
|
29
|
+
<a
|
|
30
|
+
href=${item.url}
|
|
31
|
+
data-glean-id=${`homepage: news ${index + 1} -> ${item.url}`}
|
|
32
|
+
>${item.title}</a
|
|
33
|
+
>
|
|
27
34
|
</h3>
|
|
28
35
|
<time class="latest-news__date" datetime=${item.published_at}>
|
|
29
36
|
${rtf.format(
|
|
@@ -16,7 +16,7 @@ export class MDNLoginButton extends L10nMixin(LitElement) {
|
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
render() {
|
|
19
|
-
return html`<mdn-button href=${this._loginUrl}
|
|
19
|
+
return html`<mdn-button href=${this._loginUrl} data-glean-id="login_button"
|
|
20
20
|
>${this.l10n("login-button-login")`Login`}</mdn-button
|
|
21
21
|
>`;
|
|
22
22
|
}
|
|
@@ -71,7 +71,9 @@ export class Menu extends ServerComponent {
|
|
|
71
71
|
data-glean-id=${`menu_click_link: top-level -> ${tab.href}`}
|
|
72
72
|
>${tab.buttonText}</a
|
|
73
73
|
>`
|
|
74
|
-
: html`<mdn-dropdown
|
|
74
|
+
: html`<mdn-dropdown
|
|
75
|
+
data-glean-toggle-open=${`menu_toggle: ${tab.id}`}
|
|
76
|
+
>
|
|
75
77
|
<button class="menu__tab-button" type="button" slot="button">
|
|
76
78
|
${typeof tab.buttonText === "string"
|
|
77
79
|
? html`<span class="menu__tab-label"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LitElement, html, nothing } from "lit";
|
|
2
2
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
3
3
|
|
|
4
|
+
import { gleanClick } from "../../utils/glean.js";
|
|
4
5
|
import { OBSERVATORY_API_URL } from "../env/index.js";
|
|
5
6
|
import "../progress-bar/element.js";
|
|
6
7
|
import "../button/element.js";
|
|
@@ -61,6 +62,7 @@ export class MDNObservatoryForm extends LitElement {
|
|
|
61
62
|
this._hostname = host;
|
|
62
63
|
}
|
|
63
64
|
this._queryRunning = true;
|
|
65
|
+
gleanClick("observatory: scan");
|
|
64
66
|
try {
|
|
65
67
|
const apiUrl = new URL(
|
|
66
68
|
OBSERVATORY_API_URL +
|
|
@@ -77,6 +79,7 @@ export class MDNObservatoryForm extends LitElement {
|
|
|
77
79
|
} catch (error) {
|
|
78
80
|
// @ts-expect-error
|
|
79
81
|
this._errorMessage = `${ERROR_MAP[error.name] || "message" in error ? error["message"] : error}`;
|
|
82
|
+
gleanClick(`observatory: error -> ${this._errorMessage}`);
|
|
80
83
|
} finally {
|
|
81
84
|
this._queryRunning = false;
|
|
82
85
|
}
|
|
@@ -2,6 +2,7 @@ import { Task } from "@lit/task";
|
|
|
2
2
|
import { LitElement, html } from "lit";
|
|
3
3
|
import { nothing } from "lit";
|
|
4
4
|
|
|
5
|
+
import { gleanClick } from "../../utils/glean.js";
|
|
5
6
|
import { OBSERVATORY_API_URL } from "../env/index.js";
|
|
6
7
|
|
|
7
8
|
import styles from "./element.css?lit";
|
|
@@ -62,7 +63,9 @@ export class MDNObservatoryResults extends LitElement {
|
|
|
62
63
|
}
|
|
63
64
|
return await res.json();
|
|
64
65
|
} catch (error) {
|
|
65
|
-
|
|
66
|
+
const message = "Observatory API request for scan data failed";
|
|
67
|
+
gleanClick(`observatory: error -> ${message}`);
|
|
68
|
+
throw new Error(message, {
|
|
66
69
|
cause: error,
|
|
67
70
|
});
|
|
68
71
|
}
|
|
@@ -116,6 +119,7 @@ export class MDNObservatoryResults extends LitElement {
|
|
|
116
119
|
if (!this.host) {
|
|
117
120
|
return;
|
|
118
121
|
}
|
|
122
|
+
gleanClick("observatory: rescan");
|
|
119
123
|
this._usePostInApi = true;
|
|
120
124
|
this._apiTask.run();
|
|
121
125
|
}
|
|
@@ -127,6 +131,7 @@ export class MDNObservatoryResults extends LitElement {
|
|
|
127
131
|
*/
|
|
128
132
|
_handleTabSelect(index, key) {
|
|
129
133
|
this.selectedTab = index;
|
|
134
|
+
gleanClick(`observatory: tab -> ${key}`);
|
|
130
135
|
globalThis.history.replaceState(
|
|
131
136
|
"",
|
|
132
137
|
"",
|
|
@@ -65,7 +65,12 @@ export function Rating({ result, host, rescan }) {
|
|
|
65
65
|
@click=${rescan}
|
|
66
66
|
></mdn-observatory-rescan-button>
|
|
67
67
|
<div class="scan-another">
|
|
68
|
-
<a
|
|
68
|
+
<a
|
|
69
|
+
href="/en-US/observatory"
|
|
70
|
+
data-glean-id="observatory: scan-another"
|
|
71
|
+
>
|
|
72
|
+
Scan another website
|
|
73
|
+
</a>
|
|
69
74
|
</div>
|
|
70
75
|
</section>
|
|
71
76
|
</section>
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { LitElement, html, nothing } from "lit";
|
|
2
|
-
import { ref } from "lit/directives/ref.js";
|
|
2
|
+
import { createRef, ref } from "lit/directives/ref.js";
|
|
3
3
|
import { styleMap } from "lit/directives/style-map.js";
|
|
4
4
|
|
|
5
|
+
import { gleanClick } from "../../utils/glean.js";
|
|
6
|
+
import { PlacementMixin } from "../placement/mixin.js";
|
|
7
|
+
import { ViewedController } from "../viewed-controller/viewed-controller.js";
|
|
8
|
+
|
|
5
9
|
import "../placement-note/element.js";
|
|
6
10
|
import "../placement-no/element.js";
|
|
7
11
|
|
|
8
|
-
import { PlacementMixin } from "../placement/mixin.js";
|
|
9
|
-
|
|
10
12
|
import styles from "./element.css?lit";
|
|
11
13
|
|
|
12
14
|
/**
|
|
@@ -17,6 +19,16 @@ import styles from "./element.css?lit";
|
|
|
17
19
|
export class MDNPlacementTop extends PlacementMixin(LitElement) {
|
|
18
20
|
static styles = styles;
|
|
19
21
|
|
|
22
|
+
/** @type {import("lit/directives/ref.js").Ref<HTMLElement>} */
|
|
23
|
+
_fallbackRef = createRef();
|
|
24
|
+
|
|
25
|
+
constructor() {
|
|
26
|
+
super();
|
|
27
|
+
new ViewedController(this, this._fallbackRef, () => {
|
|
28
|
+
gleanClick("banner_scrimba_view");
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
20
32
|
/**
|
|
21
33
|
*
|
|
22
34
|
* @returns {TemplateResult | symbol}
|
|
@@ -27,7 +39,7 @@ export class MDNPlacementTop extends PlacementMixin(LitElement) {
|
|
|
27
39
|
|
|
28
40
|
renderFallback() {
|
|
29
41
|
return html`
|
|
30
|
-
<div class="fallback">
|
|
42
|
+
<div ${ref(this._fallbackRef)} class="fallback">
|
|
31
43
|
<p class="fallback__copy">
|
|
32
44
|
Learn frontend, backend, and AI from our course partner
|
|
33
45
|
<a
|
|
@@ -342,6 +342,7 @@ ${"```"}`,
|
|
|
342
342
|
@click=${this._share}
|
|
343
343
|
?disabled=${!hasCode}
|
|
344
344
|
data-id="share"
|
|
345
|
+
data-glean-id="playground: share-click"
|
|
345
346
|
>${this.l10n("playground-share")`Share`}</mdn-button
|
|
346
347
|
>
|
|
347
348
|
<mdn-button
|
|
@@ -356,6 +357,7 @@ ${"```"}`,
|
|
|
356
357
|
variant="secondary"
|
|
357
358
|
@click=${this._reset}
|
|
358
359
|
?disabled=${!isResettable}
|
|
360
|
+
data-glean-id="playground: reset-click"
|
|
359
361
|
>${this.l10n("playground-reset")`Reset`}</mdn-button
|
|
360
362
|
>`
|
|
361
363
|
: nothing}
|
|
@@ -391,6 +393,7 @@ ${"```"}`,
|
|
|
391
393
|
@click=${this._reportOpen}
|
|
392
394
|
variant="secondary"
|
|
393
395
|
.icon=${warningIcon}
|
|
396
|
+
data-glean-id="playground: flag-click"
|
|
394
397
|
>
|
|
395
398
|
${this.l10n(
|
|
396
399
|
"playground-seeing-something-inappropriate",
|
|
@@ -437,8 +440,14 @@ ${"```"}`,
|
|
|
437
440
|
)`Share your code via Permalink`}
|
|
438
441
|
</h2>
|
|
439
442
|
${this._user.render({
|
|
440
|
-
initial: () =>
|
|
441
|
-
|
|
443
|
+
initial: () =>
|
|
444
|
+
html`<mdn-login-button
|
|
445
|
+
data-glean-id="playground: banner-login"
|
|
446
|
+
></mdn-login-button>`,
|
|
447
|
+
pending: () =>
|
|
448
|
+
html`<mdn-login-button
|
|
449
|
+
data-glean-id="playground: banner-login"
|
|
450
|
+
></mdn-login-button>`,
|
|
442
451
|
complete: (user) =>
|
|
443
452
|
user.isAuthenticated
|
|
444
453
|
? this._permalink && !isResettable
|
|
@@ -453,12 +462,16 @@ ${"```"}`,
|
|
|
453
462
|
)`Copy to clipboard`}</mdn-button
|
|
454
463
|
>
|
|
455
464
|
`
|
|
456
|
-
: html`<mdn-button
|
|
465
|
+
: html`<mdn-button
|
|
466
|
+
@click=${this._createPermalink}
|
|
467
|
+
data-glean-id="playground: share-permalink"
|
|
457
468
|
>${this.l10n(
|
|
458
469
|
"playground-create-link",
|
|
459
470
|
)`Create link`}</mdn-button
|
|
460
471
|
>`
|
|
461
|
-
: html`<mdn-login-button
|
|
472
|
+
: html`<mdn-login-button
|
|
473
|
+
data-glean-id="playground: banner-login"
|
|
474
|
+
></mdn-login-button>`,
|
|
462
475
|
})}
|
|
463
476
|
</section>
|
|
464
477
|
</mdn-modal>
|
|
@@ -33,7 +33,10 @@ export class RecentContributions extends ServerComponent {
|
|
|
33
33
|
)}
|
|
34
34
|
</time>
|
|
35
35
|
<div class="recent-contributions__title">
|
|
36
|
-
<a
|
|
36
|
+
<a
|
|
37
|
+
class="external"
|
|
38
|
+
href=${contribution.url}
|
|
39
|
+
data-glean-id=${`homepage: contribution ${index + 1} -> ${contribution.url}`}
|
|
37
40
|
>${contribution.title}</a
|
|
38
41
|
>
|
|
39
42
|
</div>
|
|
@@ -21,7 +21,11 @@ export class ReferenceToc extends ServerComponent {
|
|
|
21
21
|
<ul>
|
|
22
22
|
${toc?.map(
|
|
23
23
|
({ id, text }) =>
|
|
24
|
-
html`<li
|
|
24
|
+
html`<li>
|
|
25
|
+
<a href="#${id}" data-glean-id="toc_click: #${id}"
|
|
26
|
+
>${unsafeHTML(text)}</a
|
|
27
|
+
>
|
|
28
|
+
</li>`,
|
|
25
29
|
)}
|
|
26
30
|
</ul>
|
|
27
31
|
</nav>`;
|