1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
import { LitElement } from "chrome://global/content/vendor/lit.all.mjs";
/**
* Helper for our replacement of @query. Used with `static queries` property.
*
* https://github.com/lit/lit/blob/main/packages/reactive-element/src/decorators/query.ts
*/
function query(el, selector) {
return () => el.renderRoot.querySelector(selector);
}
/**
* Helper for our replacement of @queryAll. Used with `static queries` property.
*
* https://github.com/lit/lit/blob/main/packages/reactive-element/src/decorators/query-all.ts
*/
function queryAll(el, selector) {
return () => el.renderRoot.querySelectorAll(selector);
}
/**
* MozLitElement provides extensions to the lit-provided LitElement class.
*
*******
*
* `@query` support (define a getter for a querySelector):
*
* static get queries() {
* return {
* propertyName: ".aNormal .cssSelector",
* anotherName: { all: ".selectorFor .querySelectorAll" },
* };
* }
*
* This example would add properties that would be written like this without
* using `queries`:
*
* get propertyName() {
* return this.renderRoot?.querySelector(".aNormal .cssSelector");
* }
*
* get anotherName() {
* return this.renderRoot?.querySelectorAll(".selectorFor .querySelectorAll");
* }
*******
*
* Automatic Fluent support for shadow DOM.
*
* Fluent requires that a shadowRoot be connected before it can use Fluent.
* Shadow roots will get connected automatically.
*
*******
*
* Test helper for sending events after a change: `dispatchOnUpdateComplete`
*
* When some async stuff is going on and you want to wait for it in a test, you
* can use `this.dispatchOnUpdateComplete(myEvent)` and have the test wait on
* your event.
*
* The component will then wait for your reactive property change to take effect
* and dispatch the desired event.
*
* Example:
*
* async onClick() {
* let response = await this.getServerResponse(this.data);
* // Show the response status to the user.
* this.responseStatus = respose.status;
* this.dispatchOnUpdateComplete(
* new CustomEvent("status-shown")
* );
* }
*
* add_task(async testButton() {
* let button = this.setupAndGetButton();
* button.click();
* await BrowserTestUtils.waitForEvent(button, "status-shown");
* });
*/
export class MozLitElement extends LitElement {
constructor() {
super();
let { queries } = this.constructor;
if (queries) {
for (let [selectorName, selector] of Object.entries(queries)) {
if (selector.all) {
Object.defineProperty(this, selectorName, {
get: queryAll(this, selector.all),
});
} else {
Object.defineProperty(this, selectorName, {
get: query(this, selector),
});
}
}
}
}
connectedCallback() {
super.connectedCallback();
if (
this.renderRoot == this.shadowRoot &&
!this._l10nRootConnected &&
document.l10n
) {
document.l10n.connectRoot(this.renderRoot);
this._l10nRootConnected = true;
}
}
async dispatchOnUpdateComplete(event) {
await this.updateComplete;
this.dispatchEvent(event);
}
update() {
super.update();
if (document.l10n) {
document.l10n.translateFragment(this.renderRoot);
}
}
}
|