chrome-devtools-frontend 1.0.945579 → 1.0.945677
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/front_end/panels/animation/AnimationTimeline.ts +1 -1
- package/front_end/panels/network/NetworkItemView.ts +7 -1
- package/front_end/panels/profiler/heapProfiler.css +2 -5
- package/front_end/panels/webauthn/WebauthnPane.ts +31 -32
- package/front_end/ui/components/buttons/Button.ts +17 -0
- package/front_end/ui/components/buttons/button.css +31 -0
- package/front_end/ui/components/data_grid/DataGrid.ts +9 -0
- package/front_end/ui/components/docs/button/basic.ts +42 -0
- package/front_end/ui/components/text_editor/TextEditor.ts +5 -2
- package/front_end/ui/legacy/ListWidget.ts +2 -2
- package/package.json +1 -1
- package/scripts/eslint_rules/lib/l10n_filename_matches.js +17 -4
- package/scripts/eslint_rules/tests/l10n_filename_matches_test.js +21 -0
|
@@ -332,7 +332,7 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
332
332
|
show: (popover: UI.GlassPane.GlassPane): Promise<boolean> => {
|
|
333
333
|
let animGroup;
|
|
334
334
|
for (const [group, previewUI] of this.#previewMap) {
|
|
335
|
-
if (previewUI.element === element.parentElement) {
|
|
335
|
+
if (previewUI.element === element || previewUI.element === element.parentElement) {
|
|
336
336
|
animGroup = group;
|
|
337
337
|
}
|
|
338
338
|
}
|
|
@@ -270,7 +270,13 @@ export class NetworkItemView extends UI.TabbedPane.TabbedPane {
|
|
|
270
270
|
|
|
271
271
|
private selectTabInternal(tabId: string): void {
|
|
272
272
|
if (!this.selectTab(tabId)) {
|
|
273
|
-
|
|
273
|
+
// maybeAppendPayloadPanel might cause payload tab to appear asynchronously, so
|
|
274
|
+
// it makes sense to retry on the next tick
|
|
275
|
+
setTimeout(() => {
|
|
276
|
+
if (!this.selectTab(tabId)) {
|
|
277
|
+
this.selectTab('headers');
|
|
278
|
+
}
|
|
279
|
+
}, 0);
|
|
274
280
|
}
|
|
275
281
|
}
|
|
276
282
|
|
|
@@ -132,11 +132,8 @@
|
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
.heap-snapshot-view tr:not(.selected) td.object-column span.heap-object-tag
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
.heap-snapshot-view td.object-column span.grayed {
|
|
135
|
+
.heap-snapshot-view tr:not(.selected) td.object-column span.heap-object-tag,
|
|
136
|
+
.heap-snapshot-view tr:not(.selected) td.object-column span.grayed {
|
|
140
137
|
color: var(--color-text-secondary);
|
|
141
138
|
}
|
|
142
139
|
|
|
@@ -227,15 +227,15 @@ const PROTOCOL_AUTHENTICATOR_VALUES: Protocol.EnumerableEnum<typeof Protocol.Web
|
|
|
227
227
|
U2f: Protocol.WebAuthn.AuthenticatorProtocol.U2f,
|
|
228
228
|
};
|
|
229
229
|
|
|
230
|
-
export class WebauthnPaneImpl extends UI.Widget.VBox
|
|
231
|
-
|
|
232
|
-
private activeAuthId: Protocol.WebAuthn.AuthenticatorId|null;
|
|
233
|
-
private hasBeenEnabled
|
|
234
|
-
private readonly dataGrids
|
|
235
|
-
|
|
236
|
-
private enableCheckbox
|
|
230
|
+
export class WebauthnPaneImpl extends UI.Widget.VBox implements
|
|
231
|
+
SDK.TargetManager.SDKModelObserver<SDK.WebAuthnModel.WebAuthnModel> {
|
|
232
|
+
private activeAuthId: Protocol.WebAuthn.AuthenticatorId|null = null;
|
|
233
|
+
private hasBeenEnabled = false;
|
|
234
|
+
private readonly dataGrids =
|
|
235
|
+
new Map<Protocol.WebAuthn.AuthenticatorId, DataGrid.DataGrid.DataGridImpl<DataGridNode>>();
|
|
236
|
+
private enableCheckbox!: UI.Toolbar.ToolbarCheckbox;
|
|
237
237
|
private readonly availableAuthenticatorSetting: Common.Settings.Setting<AvailableAuthenticatorOptions[]>;
|
|
238
|
-
private model
|
|
238
|
+
private model?: SDK.WebAuthnModel.WebAuthnModel;
|
|
239
239
|
private authenticatorsView: HTMLElement;
|
|
240
240
|
private topToolbarContainer: HTMLElement|undefined;
|
|
241
241
|
private topToolbar: UI.Toolbar.Toolbar|undefined;
|
|
@@ -253,21 +253,13 @@ export class WebauthnPaneImpl extends UI.Widget.VBox {
|
|
|
253
253
|
|
|
254
254
|
constructor() {
|
|
255
255
|
super(true);
|
|
256
|
+
SDK.TargetManager.TargetManager.instance().observeModels(SDK.WebAuthnModel.WebAuthnModel, this);
|
|
256
257
|
|
|
257
258
|
this.contentElement.classList.add('webauthn-pane');
|
|
258
|
-
this.enabled = false;
|
|
259
|
-
this.activeAuthId = null;
|
|
260
|
-
this.hasBeenEnabled = false;
|
|
261
|
-
this.dataGrids = new Map();
|
|
262
259
|
|
|
263
260
|
this.availableAuthenticatorSetting =
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
const mainTarget = SDK.TargetManager.TargetManager.instance().mainTarget();
|
|
268
|
-
if (mainTarget) {
|
|
269
|
-
this.model = mainTarget.model(SDK.WebAuthnModel.WebAuthnModel);
|
|
270
|
-
}
|
|
261
|
+
Common.Settings.Settings.instance().createSetting<AvailableAuthenticatorOptions[]>(
|
|
262
|
+
'webauthnAuthenticators', []);
|
|
271
263
|
|
|
272
264
|
this.createToolbar();
|
|
273
265
|
this.authenticatorsView = this.contentElement.createChild('div', 'authenticators-view');
|
|
@@ -284,6 +276,18 @@ export class WebauthnPaneImpl extends UI.Widget.VBox {
|
|
|
284
276
|
return webauthnPaneImplInstance;
|
|
285
277
|
}
|
|
286
278
|
|
|
279
|
+
modelAdded(model: SDK.WebAuthnModel.WebAuthnModel): void {
|
|
280
|
+
if (model.target() === SDK.TargetManager.TargetManager.instance().mainTarget()) {
|
|
281
|
+
this.model = model;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
modelRemoved(model: SDK.WebAuthnModel.WebAuthnModel): void {
|
|
286
|
+
if (model.target() === SDK.TargetManager.TargetManager.instance().mainTarget()) {
|
|
287
|
+
this.model = undefined;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
287
291
|
private async loadInitialAuthenticators(): Promise<void> {
|
|
288
292
|
let activeAuthenticatorId: Protocol.WebAuthn.AuthenticatorId|null = null;
|
|
289
293
|
const availableAuthenticators = this.availableAuthenticatorSetting.get();
|
|
@@ -422,7 +426,6 @@ export class WebauthnPaneImpl extends UI.Widget.VBox {
|
|
|
422
426
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.VirtualAuthenticatorEnvironmentEnabled);
|
|
423
427
|
this.hasBeenEnabled = true;
|
|
424
428
|
}
|
|
425
|
-
this.enabled = enable;
|
|
426
429
|
if (this.model) {
|
|
427
430
|
await this.model.setVirtualAuthEnvEnabled(enable);
|
|
428
431
|
}
|
|
@@ -609,7 +612,7 @@ export class WebauthnPaneImpl extends UI.Widget.VBox {
|
|
|
609
612
|
UI.UIUtils.createRadioLabel(`active-authenticator-${authenticatorId}`, i18nString(UIStrings.active));
|
|
610
613
|
activeLabel.radioElement.addEventListener('click', this.setActiveAuthenticator.bind(this, authenticatorId));
|
|
611
614
|
activeButtonContainer.appendChild(activeLabel);
|
|
612
|
-
|
|
615
|
+
(activeLabel.radioElement as HTMLInputElement).checked = true;
|
|
613
616
|
this.activeAuthId = authenticatorId; // Newly added authenticator is automatically set as active.
|
|
614
617
|
|
|
615
618
|
const removeButton = headerElement.createChild('button', 'text-button');
|
|
@@ -783,19 +786,16 @@ export class WebauthnPaneImpl extends UI.Widget.VBox {
|
|
|
783
786
|
throw new Error('Unable to create options from current inputs');
|
|
784
787
|
}
|
|
785
788
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
transport: this.transportSelect.options[this.transportSelect.selectedIndex].value,
|
|
789
|
+
return {
|
|
790
|
+
protocol: this.protocolSelect.options[this.protocolSelect.selectedIndex].value as
|
|
791
|
+
Protocol.WebAuthn.AuthenticatorProtocol,
|
|
792
|
+
transport: this.transportSelect.options[this.transportSelect.selectedIndex].value as
|
|
793
|
+
Protocol.WebAuthn.AuthenticatorTransport,
|
|
792
794
|
hasResidentKey: this.residentKeyCheckbox.checked,
|
|
793
795
|
hasUserVerification: this.userVerificationCheckbox.checked,
|
|
794
796
|
automaticPresenceSimulation: true,
|
|
795
797
|
isUserVerified: true,
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
return options;
|
|
798
|
+
};
|
|
799
799
|
}
|
|
800
800
|
|
|
801
801
|
/**
|
|
@@ -824,8 +824,7 @@ export class WebauthnPaneImpl extends UI.Widget.VBox {
|
|
|
824
824
|
if (!button) {
|
|
825
825
|
return;
|
|
826
826
|
}
|
|
827
|
-
button.checked =
|
|
828
|
-
/** @type {!HTMLElement} */ (authenticator as HTMLElement).dataset.authenticatorId === this.activeAuthId;
|
|
827
|
+
button.checked = (authenticator as HTMLElement).dataset.authenticatorId === this.activeAuthId;
|
|
829
828
|
});
|
|
830
829
|
}
|
|
831
830
|
|
|
@@ -33,6 +33,7 @@ interface ButtonState {
|
|
|
33
33
|
size?: Size;
|
|
34
34
|
disabled: boolean;
|
|
35
35
|
active: boolean;
|
|
36
|
+
spinner?: boolean;
|
|
36
37
|
type: ButtonType;
|
|
37
38
|
value?: string;
|
|
38
39
|
}
|
|
@@ -43,6 +44,7 @@ export type ButtonData = {
|
|
|
43
44
|
size?: Size,
|
|
44
45
|
disabled?: boolean,
|
|
45
46
|
active?: boolean,
|
|
47
|
+
spinner?: boolean,
|
|
46
48
|
type?: ButtonType,
|
|
47
49
|
value?: string,
|
|
48
50
|
}|{
|
|
@@ -51,6 +53,7 @@ export type ButtonData = {
|
|
|
51
53
|
size?: Size,
|
|
52
54
|
disabled?: boolean,
|
|
53
55
|
active?: boolean,
|
|
56
|
+
spinner?: boolean,
|
|
54
57
|
type?: ButtonType,
|
|
55
58
|
value?: string,
|
|
56
59
|
};
|
|
@@ -74,6 +77,7 @@ export class Button extends HTMLElement {
|
|
|
74
77
|
size: Size.MEDIUM,
|
|
75
78
|
disabled: false,
|
|
76
79
|
active: false,
|
|
80
|
+
spinner: false,
|
|
77
81
|
type: 'button',
|
|
78
82
|
};
|
|
79
83
|
#isEmpty = true;
|
|
@@ -94,6 +98,7 @@ export class Button extends HTMLElement {
|
|
|
94
98
|
this.#props.iconUrl = data.iconUrl;
|
|
95
99
|
this.#props.size = data.size || Size.MEDIUM;
|
|
96
100
|
this.#props.active = Boolean(data.active);
|
|
101
|
+
this.#props.spinner = Boolean(data.spinner);
|
|
97
102
|
this.#props.type = data.type || 'button';
|
|
98
103
|
this.setDisabledProperty(data.disabled || false);
|
|
99
104
|
ComponentHelpers.ScheduledRender.scheduleRender(this, this.#boundRender);
|
|
@@ -129,6 +134,11 @@ export class Button extends HTMLElement {
|
|
|
129
134
|
ComponentHelpers.ScheduledRender.scheduleRender(this, this.#boundRender);
|
|
130
135
|
}
|
|
131
136
|
|
|
137
|
+
set spinner(spinner: boolean) {
|
|
138
|
+
this.#props.spinner = spinner;
|
|
139
|
+
ComponentHelpers.ScheduledRender.scheduleRender(this, this.#boundRender);
|
|
140
|
+
}
|
|
141
|
+
|
|
132
142
|
private setDisabledProperty(disabled: boolean): void {
|
|
133
143
|
this.#props.disabled = disabled;
|
|
134
144
|
this.toggleAttribute('disabled', disabled);
|
|
@@ -189,6 +199,12 @@ export class Button extends HTMLElement {
|
|
|
189
199
|
small: Boolean(this.#props.size === Size.SMALL),
|
|
190
200
|
active: this.#props.active,
|
|
191
201
|
};
|
|
202
|
+
const spinnerClasses = {
|
|
203
|
+
primary: this.#props.variant === Variant.PRIMARY,
|
|
204
|
+
secondary: this.#props.variant === Variant.SECONDARY,
|
|
205
|
+
disabled: Boolean(this.#props.disabled),
|
|
206
|
+
'spinner-component': true,
|
|
207
|
+
};
|
|
192
208
|
// clang-format off
|
|
193
209
|
LitHtml.render(
|
|
194
210
|
LitHtml.html`
|
|
@@ -200,6 +216,7 @@ export class Button extends HTMLElement {
|
|
|
200
216
|
} as IconButton.Icon.IconData}
|
|
201
217
|
>
|
|
202
218
|
</${IconButton.Icon.Icon.litTagName}>` : ''}
|
|
219
|
+
${this.#props.spinner ? LitHtml.html`<span class=${LitHtml.Directives.classMap(spinnerClasses)}></span>` : ''}
|
|
203
220
|
<slot @slotchange=${this.onSlotChange}></slot>
|
|
204
221
|
</button>
|
|
205
222
|
`, this.#shadow, {host: this});
|
|
@@ -201,3 +201,34 @@ button.primary:disabled devtools-icon {
|
|
|
201
201
|
button.secondary:disabled devtools-icon {
|
|
202
202
|
--icon-color: var(--color-text-disabled);
|
|
203
203
|
}
|
|
204
|
+
|
|
205
|
+
.spinner-component.secondary {
|
|
206
|
+
border: 2px solid var(--color-primary);
|
|
207
|
+
border-right-color: transparent;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.spinner-component.disabled {
|
|
211
|
+
border: 2px solid var(--color-text-disabled);
|
|
212
|
+
border-right-color: transparent;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.spinner-component {
|
|
216
|
+
display: block;
|
|
217
|
+
width: 12px;
|
|
218
|
+
height: 12px;
|
|
219
|
+
border-radius: 6px;
|
|
220
|
+
border: 2px solid var(--color-background);
|
|
221
|
+
animation: spinner-animation 1s linear infinite;
|
|
222
|
+
border-right-color: transparent;
|
|
223
|
+
margin-right: 6px;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
@keyframes spinner-animation {
|
|
227
|
+
from {
|
|
228
|
+
transform: rotate(0);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
to {
|
|
232
|
+
transform: rotate(360deg);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
@@ -832,6 +832,15 @@ export class DataGrid extends HTMLElement {
|
|
|
832
832
|
}
|
|
833
833
|
this.scrollToBottomIfRequired();
|
|
834
834
|
this.engageResizeObserver();
|
|
835
|
+
if (this.#hasRenderedAtLeastOnce) {
|
|
836
|
+
// We may have had a cell's width change on a re-render, or it may have
|
|
837
|
+
// been hidden entirely, so we need to ensure that the resize handlers are
|
|
838
|
+
// re-positioned correctly if so.
|
|
839
|
+
|
|
840
|
+
// We don't have to do this on first render as it will fire when the resize observer is engaged.
|
|
841
|
+
this.alignScrollHandlers();
|
|
842
|
+
}
|
|
843
|
+
|
|
835
844
|
this.#isRendering = false;
|
|
836
845
|
this.#hasRenderedAtLeastOnce = true;
|
|
837
846
|
|
|
@@ -42,6 +42,16 @@ forcedActive.innerText = 'Forced active';
|
|
|
42
42
|
forcedActive.onclick = () => alert('clicked');
|
|
43
43
|
appendButton(forcedActive);
|
|
44
44
|
|
|
45
|
+
// Primary (forced spinner)
|
|
46
|
+
const forcedSpinner = new Buttons.Button.Button();
|
|
47
|
+
forcedSpinner.data = {
|
|
48
|
+
variant: Buttons.Button.Variant.PRIMARY,
|
|
49
|
+
spinner: true,
|
|
50
|
+
};
|
|
51
|
+
forcedSpinner.innerText = 'Forced spinner';
|
|
52
|
+
forcedSpinner.onclick = () => alert('clicked');
|
|
53
|
+
appendButton(forcedSpinner);
|
|
54
|
+
|
|
45
55
|
// Secondary
|
|
46
56
|
const secondaryButton = new Buttons.Button.Button();
|
|
47
57
|
secondaryButton.innerText = 'Click me';
|
|
@@ -51,6 +61,16 @@ secondaryButton.data = {
|
|
|
51
61
|
};
|
|
52
62
|
appendButton(secondaryButton);
|
|
53
63
|
|
|
64
|
+
// Secondary spinner
|
|
65
|
+
const secondarySpinnerButton = new Buttons.Button.Button();
|
|
66
|
+
secondarySpinnerButton.innerText = 'Click me';
|
|
67
|
+
secondarySpinnerButton.onclick = () => alert('clicked');
|
|
68
|
+
secondarySpinnerButton.data = {
|
|
69
|
+
variant: Buttons.Button.Variant.SECONDARY,
|
|
70
|
+
spinner: true,
|
|
71
|
+
};
|
|
72
|
+
appendButton(secondarySpinnerButton);
|
|
73
|
+
|
|
54
74
|
// Primary
|
|
55
75
|
const disabledPrimaryButtons = new Buttons.Button.Button();
|
|
56
76
|
disabledPrimaryButtons.data = {
|
|
@@ -61,6 +81,17 @@ disabledPrimaryButtons.innerText = 'Cannot click me';
|
|
|
61
81
|
disabledPrimaryButtons.onclick = () => alert('clicked');
|
|
62
82
|
appendButton(disabledPrimaryButtons);
|
|
63
83
|
|
|
84
|
+
// Primary spinner
|
|
85
|
+
const disabledSpinnerPrimaryButtons = new Buttons.Button.Button();
|
|
86
|
+
disabledSpinnerPrimaryButtons.data = {
|
|
87
|
+
variant: Buttons.Button.Variant.PRIMARY,
|
|
88
|
+
disabled: true,
|
|
89
|
+
spinner: true,
|
|
90
|
+
};
|
|
91
|
+
disabledSpinnerPrimaryButtons.innerText = 'Cannot click me';
|
|
92
|
+
disabledSpinnerPrimaryButtons.onclick = () => alert('clicked');
|
|
93
|
+
appendButton(disabledSpinnerPrimaryButtons);
|
|
94
|
+
|
|
64
95
|
// Secondary
|
|
65
96
|
const disabledSecondaryButton = new Buttons.Button.Button();
|
|
66
97
|
disabledSecondaryButton.innerText = 'Cannot click me';
|
|
@@ -71,6 +102,17 @@ disabledSecondaryButton.data = {
|
|
|
71
102
|
};
|
|
72
103
|
appendButton(disabledSecondaryButton);
|
|
73
104
|
|
|
105
|
+
// Secondary spinner
|
|
106
|
+
const disabledSpinnerSecondaryButton = new Buttons.Button.Button();
|
|
107
|
+
disabledSpinnerSecondaryButton.innerText = 'Cannot click me';
|
|
108
|
+
disabledSpinnerSecondaryButton.onclick = () => alert('clicked');
|
|
109
|
+
disabledSpinnerSecondaryButton.data = {
|
|
110
|
+
variant: Buttons.Button.Variant.SECONDARY,
|
|
111
|
+
disabled: true,
|
|
112
|
+
spinner: true,
|
|
113
|
+
};
|
|
114
|
+
appendButton(disabledSpinnerSecondaryButton);
|
|
115
|
+
|
|
74
116
|
// Primary Icon
|
|
75
117
|
const primaryIconButton = new Buttons.Button.Button();
|
|
76
118
|
primaryIconButton.innerText = 'Click me';
|
|
@@ -28,7 +28,7 @@ export class TextEditor extends HTMLElement {
|
|
|
28
28
|
#pendingState: CodeMirror.EditorState|undefined;
|
|
29
29
|
#lastScrollPos = {left: 0, top: 0};
|
|
30
30
|
#resizeTimeout = -1;
|
|
31
|
-
#
|
|
31
|
+
#resizeListener = (): void => {
|
|
32
32
|
if (this.#resizeTimeout < 0) {
|
|
33
33
|
this.#resizeTimeout = window.setTimeout(() => {
|
|
34
34
|
this.#resizeTimeout = -1;
|
|
@@ -37,7 +37,8 @@ export class TextEditor extends HTMLElement {
|
|
|
37
37
|
}
|
|
38
38
|
}, 50);
|
|
39
39
|
}
|
|
40
|
-
}
|
|
40
|
+
};
|
|
41
|
+
#devtoolsResizeObserver = new ResizeObserver(this.#resizeListener);
|
|
41
42
|
|
|
42
43
|
constructor(pendingState?: CodeMirror.EditorState) {
|
|
43
44
|
super();
|
|
@@ -104,6 +105,7 @@ export class TextEditor extends HTMLElement {
|
|
|
104
105
|
if (this.#activeEditor) {
|
|
105
106
|
this.#pendingState = this.#activeEditor.state;
|
|
106
107
|
this.#devtoolsResizeObserver.disconnect();
|
|
108
|
+
window.removeEventListener('resize', this.#resizeListener);
|
|
107
109
|
this.#activeEditor.destroy();
|
|
108
110
|
this.#activeEditor = undefined;
|
|
109
111
|
this.ensureSettingListeners();
|
|
@@ -148,6 +150,7 @@ export class TextEditor extends HTMLElement {
|
|
|
148
150
|
if (devtoolsElement) {
|
|
149
151
|
this.#devtoolsResizeObserver.observe(devtoolsElement);
|
|
150
152
|
}
|
|
153
|
+
window.addEventListener('resize', this.#resizeListener);
|
|
151
154
|
}
|
|
152
155
|
|
|
153
156
|
revealPosition(selection: CodeMirror.EditorSelection, highlight: boolean = true): void {
|
|
@@ -276,10 +276,10 @@ export class Editor<T> {
|
|
|
276
276
|
this.element = document.createElement('div');
|
|
277
277
|
this.element.classList.add('editor-container');
|
|
278
278
|
this.element.addEventListener('keydown', onKeyDown.bind(null, isEscKey, this.cancelClicked.bind(this)), false);
|
|
279
|
-
this.element.addEventListener(
|
|
280
|
-
'keydown', onKeyDown.bind(null, event => event.key === 'Enter', this.commitClicked.bind(this)), false);
|
|
281
279
|
|
|
282
280
|
this.contentElementInternal = this.element.createChild('div', 'editor-content');
|
|
281
|
+
this.contentElementInternal.addEventListener(
|
|
282
|
+
'keydown', onKeyDown.bind(null, event => event.key === 'Enter', this.commitClicked.bind(this)), false);
|
|
283
283
|
|
|
284
284
|
const buttonsRow = this.element.createChild('div', 'editor-buttons');
|
|
285
285
|
this.commitButton = createTextButton('', this.commitClicked.bind(this), '', true /* primary */);
|
package/package.json
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
7
|
const path = require('path');
|
|
8
|
+
const {devtoolsRootPath} = require('../../devtools_paths.js');
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
+
const DEFAULT_FRONT_END_DIRECTORY = path.join(devtoolsRootPath(), 'front_end');
|
|
10
11
|
|
|
11
12
|
function isModuleScope(context) {
|
|
12
13
|
return context.getScope().type === 'module';
|
|
@@ -36,7 +37,15 @@ module.exports = {
|
|
|
36
37
|
category: 'Possible Errors',
|
|
37
38
|
},
|
|
38
39
|
fixable: 'code',
|
|
39
|
-
schema: [
|
|
40
|
+
schema: [{
|
|
41
|
+
'type': 'object',
|
|
42
|
+
'properties': {
|
|
43
|
+
'rootFrontendDirectory': {
|
|
44
|
+
'type': 'string',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
additionalProperties: false,
|
|
48
|
+
}]
|
|
40
49
|
},
|
|
41
50
|
create: function(context) {
|
|
42
51
|
return {
|
|
@@ -51,8 +60,12 @@ module.exports = {
|
|
|
51
60
|
return;
|
|
52
61
|
}
|
|
53
62
|
|
|
63
|
+
let frontEndDirectory = DEFAULT_FRONT_END_DIRECTORY;
|
|
64
|
+
if (context.options && context.options[0]?.rootFrontendDirectory) {
|
|
65
|
+
frontEndDirectory = context.options[0].rootFrontendDirectory;
|
|
66
|
+
}
|
|
54
67
|
const currentSourceFile = path.resolve(context.getFilename());
|
|
55
|
-
const currentFileRelativeToFrontEnd = path.relative(
|
|
68
|
+
const currentFileRelativeToFrontEnd = path.relative(frontEndDirectory, currentSourceFile);
|
|
56
69
|
|
|
57
70
|
const currentModuleDirectory = path.dirname(currentSourceFile);
|
|
58
71
|
const allowedPathArguments = [
|
|
@@ -62,7 +75,7 @@ module.exports = {
|
|
|
62
75
|
];
|
|
63
76
|
|
|
64
77
|
const previousFileLocationArgument = callExpression.arguments[0];
|
|
65
|
-
const actualPath = path.join(
|
|
78
|
+
const actualPath = path.join(frontEndDirectory, previousFileLocationArgument.value);
|
|
66
79
|
if (!allowedPathArguments.includes(actualPath)) {
|
|
67
80
|
const newFileName = currentFileRelativeToFrontEnd.replace(/\\/g, '/');
|
|
68
81
|
context.report({
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
7
9
|
const rule = require('../lib/l10n_filename_matches.js');
|
|
8
10
|
const ruleTester = new (require('eslint').RuleTester)({
|
|
9
11
|
parserOptions: {ecmaVersion: 9, sourceType: 'module'},
|
|
@@ -24,6 +26,16 @@ ruleTester.run('l10n_filename_matches', rule, {
|
|
|
24
26
|
code: 'const str_ = i18n.i18n.registerUIStrings(\'components/ModuleUIStrings.ts\', UIStrings);',
|
|
25
27
|
filename: 'front_end/components/test.ts',
|
|
26
28
|
},
|
|
29
|
+
{
|
|
30
|
+
code: 'const str_ = i18n.i18n.registerUIStrings(\'ModuleUIStrings.ts\', UIStrings);',
|
|
31
|
+
filename: 'front_end/components/test.ts',
|
|
32
|
+
options: [{rootFrontendDirectory: path.join(__dirname, '..', '..', '..', 'front_end', 'components')}]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
code: 'const str_ = i18n.i18n.registerUIStrings(\'test.ts\', UIStrings);',
|
|
36
|
+
filename: 'front_end/components/test.ts',
|
|
37
|
+
options: [{rootFrontendDirectory: path.join(__dirname, '..', '..', '..', 'front_end', 'components')}]
|
|
38
|
+
},
|
|
27
39
|
],
|
|
28
40
|
invalid: [
|
|
29
41
|
{
|
|
@@ -35,5 +47,14 @@ ruleTester.run('l10n_filename_matches', rule, {
|
|
|
35
47
|
}],
|
|
36
48
|
output: 'const str_ = i18n.i18n.registerUIStrings(\'components/test.ts\', UIStrings);',
|
|
37
49
|
},
|
|
50
|
+
{
|
|
51
|
+
code: 'const str_ = i18n.i18n.registerUIStrings(\'components/test.ts\', UIStrings);',
|
|
52
|
+
filename: 'front_end/components/test.ts',
|
|
53
|
+
errors: [
|
|
54
|
+
{message: 'First argument to \'registerUIStrings\' call must be \'test.ts\' or the ModuleUIStrings.(js|ts)'}
|
|
55
|
+
],
|
|
56
|
+
output: 'const str_ = i18n.i18n.registerUIStrings(\'test.ts\', UIStrings);',
|
|
57
|
+
options: [{rootFrontendDirectory: path.join(__dirname, '..', '..', '..', 'front_end', 'components')}]
|
|
58
|
+
},
|
|
38
59
|
]
|
|
39
60
|
});
|