chrome-devtools-frontend 1.0.1628368 → 1.0.1629211
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/core/host/UserMetrics.ts +0 -1
- package/front_end/core/root/ExperimentNames.ts +0 -2
- package/front_end/core/sdk/DOMModel.ts +0 -5
- package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +0 -2
- package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +0 -2
- package/front_end/entrypoints/main/MainImpl.ts +0 -3
- package/front_end/generated/InspectorBackendCommands.ts +2 -2
- package/front_end/generated/protocol.ts +5 -0
- package/front_end/models/emulation/DeviceModeModel.ts +4 -0
- package/front_end/models/issues_manager/GenericIssue.ts +18 -1
- package/front_end/models/issues_manager/descriptions/genericBackUINavigationWouldSkipAd.md +4 -0
- package/front_end/panels/common/freDialog.css +1 -0
- package/front_end/panels/elements/StylesSidebarPane.ts +1 -1
- package/front_end/panels/elements/elements-meta.ts +0 -25
- package/front_end/panels/elements/elements.ts +0 -3
- package/front_end/panels/emulation/DeviceModeToolbar.ts +335 -248
- package/front_end/panels/profiler/ProfilesPanel.ts +7 -1
- package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +29 -18
- package/front_end/panels/sources/sources-meta.ts +7 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/legacy/TabbedPane.ts +142 -16
- package/front_end/ui/legacy/TextPrompt.docs.ts +51 -0
- package/front_end/ui/legacy/TextPrompt.ts +55 -6
- package/front_end/ui/legacy/Toolbar.ts +2 -1
- package/front_end/ui/legacy/View.ts +2 -1
- package/front_end/ui/legacy/ViewManager.ts +11 -5
- package/front_end/ui/legacy/textPrompt.css +4 -0
- package/mcp/mcp.ts +1 -0
- package/package.json +1 -1
- package/front_end/panels/elements/NodeStackTraceWidget.ts +0 -76
- package/front_end/panels/elements/nodeStackTraceWidget.css +0 -11
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// Copyright 2016 The Chromium Authors
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
|
-
/* eslint-disable @devtools/no-imperative-dom-api */
|
|
5
|
-
/* eslint-disable @devtools/no-lit-render-outside-of-view */
|
|
6
4
|
|
|
7
5
|
import '../../ui/legacy/legacy.js';
|
|
8
6
|
|
|
@@ -13,10 +11,58 @@ import * as Platform from '../../core/platform/platform.js';
|
|
|
13
11
|
import * as EmulationModel from '../../models/emulation/emulation.js';
|
|
14
12
|
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
15
13
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
16
|
-
import {Directives, html, i18nTemplate, type LitTemplate, render} from '../../ui/lit/lit.js';
|
|
14
|
+
import {Directive, Directives, html, i18nTemplate, type LitTemplate, noChange, render} from '../../ui/lit/lit.js';
|
|
17
15
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
18
16
|
import * as MobileThrottling from '../mobile_throttling/mobile_throttling.js';
|
|
19
17
|
|
|
18
|
+
class AutoWidthSelectDirective extends Directive.Directive {
|
|
19
|
+
static itemWidthCache = new Map<string, string>();
|
|
20
|
+
|
|
21
|
+
constructor(partInfo: Directive.PartInfo) {
|
|
22
|
+
super(partInfo);
|
|
23
|
+
if (partInfo.type !== Directive.PartType.ELEMENT) {
|
|
24
|
+
throw new Error('AutoWidthSelectDirective must be used as an element directive');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
override update(part: Directive.ElementPart, [text]: [string]): unknown {
|
|
29
|
+
/* eslint-disable @devtools/no-imperative-dom-api */
|
|
30
|
+
const select = part.element as HTMLSelectElement;
|
|
31
|
+
|
|
32
|
+
let widthPx = AutoWidthSelectDirective.itemWidthCache.get(text);
|
|
33
|
+
if (!widthPx) {
|
|
34
|
+
const measuringElement = document.createElement('select');
|
|
35
|
+
measuringElement.className = select.className;
|
|
36
|
+
measuringElement.style.width = 'fit-content';
|
|
37
|
+
measuringElement.style.position = 'absolute';
|
|
38
|
+
measuringElement.style.visibility = 'hidden';
|
|
39
|
+
measuringElement.style.pointerEvents = 'none';
|
|
40
|
+
measuringElement.appendChild(document.createElement('option'));
|
|
41
|
+
measuringElement.options[0].textContent = text;
|
|
42
|
+
|
|
43
|
+
// Append to the select's parent so it inherits the exact same Shadow DOM styles
|
|
44
|
+
select.parentElement?.appendChild(measuringElement);
|
|
45
|
+
const width = measuringElement.offsetWidth;
|
|
46
|
+
measuringElement.remove();
|
|
47
|
+
|
|
48
|
+
widthPx = width ? `${width}px` : '';
|
|
49
|
+
if (width > 0) {
|
|
50
|
+
AutoWidthSelectDirective.itemWidthCache.set(text, widthPx);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
select.style.width = widthPx;
|
|
55
|
+
/* eslint-enable @devtools/no-imperative-dom-api */
|
|
56
|
+
return this.render(text);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
render(_text: string): unknown {
|
|
60
|
+
return noChange;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const autoWidthSelect = Directive.directive(AutoWidthSelectDirective);
|
|
65
|
+
|
|
20
66
|
const UIStrings = {
|
|
21
67
|
/**
|
|
22
68
|
* @description Title of the device dimensions selection item in the Device Mode Toolbar.
|
|
@@ -188,10 +234,226 @@ const UIStrings = {
|
|
|
188
234
|
} as const;
|
|
189
235
|
const str_ = i18n.i18n.registerUIStrings('panels/emulation/DeviceModeToolbar.ts', UIStrings);
|
|
190
236
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
191
|
-
const {ifDefined, live
|
|
237
|
+
const {ifDefined, live} = Directives;
|
|
192
238
|
const {widget} = UI.Widget;
|
|
193
239
|
const {bindToSetting} = UI.UIUtils;
|
|
194
240
|
|
|
241
|
+
export interface DeviceModeOption {
|
|
242
|
+
device: EmulationModel.EmulatedDevices.EmulatedDevice;
|
|
243
|
+
title: string;
|
|
244
|
+
selected: boolean;
|
|
245
|
+
jslogContext: string;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export interface ViewInput {
|
|
249
|
+
isResponsive: boolean;
|
|
250
|
+
isFullHeight: boolean;
|
|
251
|
+
widthValue: string;
|
|
252
|
+
heightValue: string;
|
|
253
|
+
heightPlaceholder: string;
|
|
254
|
+
modeButtonTitle: string;
|
|
255
|
+
modeButtonDisabled: boolean;
|
|
256
|
+
showSpanButton: boolean;
|
|
257
|
+
showPostureItem: boolean;
|
|
258
|
+
deviceModeOptions: {
|
|
259
|
+
responsive: {title: string, selected: boolean, jslogContext: string},
|
|
260
|
+
standard: DeviceModeOption[],
|
|
261
|
+
custom: DeviceModeOption[],
|
|
262
|
+
edit: {title: string, jslogContext: string},
|
|
263
|
+
};
|
|
264
|
+
scaleOptions: Array<{title: string, value: number, selected: boolean, jslogContext: string}>;
|
|
265
|
+
dprOptions: Array<{title: string, value: number, selected: boolean, jslogContext: string}>;
|
|
266
|
+
uaOptions: Array<{title: string, value: EmulationModel.DeviceModeModel.UA, selected: boolean, jslogContext: string}>;
|
|
267
|
+
postureOptions: Array<{title: string, value: string, selected: boolean}>;
|
|
268
|
+
selectedDeviceOption: {title: string, selected: boolean, jslogContext: string}|undefined;
|
|
269
|
+
deviceText: string;
|
|
270
|
+
scaleText: string;
|
|
271
|
+
dprText: string;
|
|
272
|
+
uaText: string;
|
|
273
|
+
postureText: string;
|
|
274
|
+
onDeviceChange: (event: Event) => void;
|
|
275
|
+
onWidthChange: (event: Event) => void;
|
|
276
|
+
onHeightChange: (event: Event) => void;
|
|
277
|
+
onScaleChange: (event: Event) => void;
|
|
278
|
+
onDeviceScaleChange: (event: Event) => void;
|
|
279
|
+
onUAChange: (event: Event) => void;
|
|
280
|
+
onPostureChange: (event: Event) => void;
|
|
281
|
+
onModeMenuClick: (event: Event) => void;
|
|
282
|
+
onSpanClick: () => void;
|
|
283
|
+
onMoreOptionsClick: (event: Event) => void;
|
|
284
|
+
autoAdjustScaleSetting: Common.Settings.Setting<boolean>;
|
|
285
|
+
showDeviceScaleFactorSetting: Common.Settings.Setting<boolean>;
|
|
286
|
+
showUserAgentTypeSetting: Common.Settings.Setting<boolean>;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export type View = (input: ViewInput, output: object, target: HTMLElement|DocumentFragment) => void;
|
|
290
|
+
|
|
291
|
+
function createSizeInput(
|
|
292
|
+
title: string, jslogContext: string, value: string|undefined, disabled: boolean|undefined,
|
|
293
|
+
placeholder: string|undefined, onChange: (event: Event) => void): LitTemplate {
|
|
294
|
+
return html`
|
|
295
|
+
<input type="number"
|
|
296
|
+
max=${EmulationModel.DeviceModeModel.MaxDeviceSize}
|
|
297
|
+
min=${EmulationModel.DeviceModeModel.MinDeviceSize}
|
|
298
|
+
title=${title}
|
|
299
|
+
class="device-mode-size-input"
|
|
300
|
+
.disabled=${disabled ?? false}
|
|
301
|
+
jslog=${VisualLogging.textField().track({change: true}).context(jslogContext)}
|
|
302
|
+
.value=${value ?? ''}
|
|
303
|
+
placeholder=${ifDefined(placeholder)}
|
|
304
|
+
@change=${onChange}
|
|
305
|
+
@keydown=${(event: Event): void => {
|
|
306
|
+
const input = event.target as HTMLInputElement;
|
|
307
|
+
let modifiedValue = UI.UIUtils.modifiedFloatNumber(Number(input.value), event);
|
|
308
|
+
if (modifiedValue === null) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
modifiedValue = Math.min(modifiedValue, EmulationModel.DeviceModeModel.MaxDeviceSize);
|
|
312
|
+
modifiedValue = Math.max(modifiedValue, EmulationModel.DeviceModeModel.MinDeviceSize);
|
|
313
|
+
|
|
314
|
+
event.preventDefault();
|
|
315
|
+
input.value = String(modifiedValue);
|
|
316
|
+
input.dispatchEvent(new Event('change'));
|
|
317
|
+
}}>`;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
321
|
+
// clang-format off
|
|
322
|
+
render(html`
|
|
323
|
+
<devtools-toolbar class="main-toolbar">
|
|
324
|
+
<div class="device-mode-empty-toolbar-element"></div>
|
|
325
|
+
${i18nTemplate(str_, UIStrings.dimensions, {PH1: html`
|
|
326
|
+
<select class="dark-text toolbar-has-dropdown-shrinkable"
|
|
327
|
+
${autoWidthSelect(input.deviceText)}
|
|
328
|
+
title=${i18nString(UIStrings.deviceType)}
|
|
329
|
+
aria-label=${i18nString(UIStrings.deviceType)}
|
|
330
|
+
@change=${input.onDeviceChange}
|
|
331
|
+
.value=${live(input.selectedDeviceOption === input.deviceModeOptions.responsive ? 'Responsive' : (input.selectedDeviceOption?.title || 'Responsive'))}
|
|
332
|
+
jslog=${VisualLogging.dropDown().track({change: true}).context('device')}>
|
|
333
|
+
<option value="Responsive" ?selected=${input.deviceModeOptions.responsive.selected} jslog=${VisualLogging.item(input.deviceModeOptions.responsive.jslogContext).track({click: true})}>
|
|
334
|
+
${input.deviceModeOptions.responsive.title}
|
|
335
|
+
</option>
|
|
336
|
+
${input.deviceModeOptions.standard.length > 0 ? html`
|
|
337
|
+
<optgroup label="Standard">
|
|
338
|
+
${input.deviceModeOptions.standard.map(o => html`<option value=${o.title} ?selected=${o.selected} jslog=${VisualLogging.item(o.jslogContext).track({click: true})}>${o.title}</option>`)}
|
|
339
|
+
</optgroup>
|
|
340
|
+
` : ''}
|
|
341
|
+
${input.deviceModeOptions.custom.length > 0 ? html`
|
|
342
|
+
<optgroup label="Custom">
|
|
343
|
+
${input.deviceModeOptions.custom.map(o => html`<option value=${o.title} ?selected=${o.selected} jslog=${VisualLogging.item(o.jslogContext).track({click: true})}>${o.title}</option>`)}
|
|
344
|
+
</optgroup>
|
|
345
|
+
` : ''}
|
|
346
|
+
<option value="Edit" jslog=${VisualLogging.item(input.deviceModeOptions.edit.jslogContext).track({click: true})}>
|
|
347
|
+
${input.deviceModeOptions.edit.title}
|
|
348
|
+
</option>
|
|
349
|
+
</select>`})}
|
|
350
|
+
|
|
351
|
+
${createSizeInput(i18nString(UIStrings.width), 'width', input.widthValue, !input.isResponsive, '', input.onWidthChange)}
|
|
352
|
+
|
|
353
|
+
<div class="device-mode-x">×</div>
|
|
354
|
+
${createSizeInput(i18nString(UIStrings.heightLeaveEmptyForFull), 'height', input.heightValue, !input.isResponsive, input.heightPlaceholder, input.onHeightChange)}
|
|
355
|
+
|
|
356
|
+
<div class="device-mode-empty-toolbar-element"></div>
|
|
357
|
+
<select class="dark-text toolbar-has-dropdown-shrinkable"
|
|
358
|
+
${autoWidthSelect(input.scaleText)}
|
|
359
|
+
title=${i18nString(UIStrings.zoom)}
|
|
360
|
+
aria-label=${i18nString(UIStrings.zoom)}
|
|
361
|
+
@change=${input.onScaleChange}
|
|
362
|
+
.value=${String(input.scaleOptions.find(o => o.selected)?.value || '')}
|
|
363
|
+
jslog=${VisualLogging.dropDown().track({change: true}).context('scale')}>
|
|
364
|
+
${input.scaleOptions.map(o => html`<option value=${o.value} ?selected=${o.selected} jslog=${VisualLogging.item(o.jslogContext).track({click: true})}>${o.title}</option>`)}
|
|
365
|
+
</select>
|
|
366
|
+
|
|
367
|
+
<devtools-button .data=${{variant: Buttons.Button.Variant.TOOLBAR, iconName: 'center-focus-weak',
|
|
368
|
+
toggledIconName: 'center-focus-weak', toggleType: Buttons.Button.ToggleType.PRIMARY} as Buttons.Button.ButtonData}
|
|
369
|
+
class="toolbar-button" title=${i18nString(UIStrings.autoadjustZoom)}
|
|
370
|
+
${bindToSetting(input.autoAdjustScaleSetting)}>
|
|
371
|
+
</devtools-button>
|
|
372
|
+
|
|
373
|
+
<div class="device-mode-empty-toolbar-element"></div>
|
|
374
|
+
|
|
375
|
+
${input.showDeviceScaleFactorSetting.get() ? html`
|
|
376
|
+
<div class="toolbar-text">
|
|
377
|
+
${i18nTemplate(str_, UIStrings.dpr, {
|
|
378
|
+
PH1: html`
|
|
379
|
+
<select class="dark-text toolbar-has-dropdown-shrinkable"
|
|
380
|
+
${autoWidthSelect(input.dprText)}
|
|
381
|
+
title=${i18nString(UIStrings.devicePixelRatio)}
|
|
382
|
+
aria-label=${i18nString(UIStrings.devicePixelRatio)}
|
|
383
|
+
@change=${input.onDeviceScaleChange}
|
|
384
|
+
.value=${String(input.dprOptions.find(o => o.selected)?.value || '')}
|
|
385
|
+
jslog=${VisualLogging.dropDown().track({change: true}).context('device-pixel-ratio')}
|
|
386
|
+
?disabled=${!input.isResponsive}>
|
|
387
|
+
${input.dprOptions.map(o => html`<option value=${o.value} ?selected=${o.selected} jslog=${VisualLogging.item(o.jslogContext).track({click: true})}>${o.title}</option>`)}
|
|
388
|
+
</select>`
|
|
389
|
+
})}
|
|
390
|
+
</div>` : ''}
|
|
391
|
+
|
|
392
|
+
<div class="device-mode-empty-toolbar-element"></div>
|
|
393
|
+
${input.showUserAgentTypeSetting.get() ? html`
|
|
394
|
+
<select class="dark-text toolbar-has-dropdown-shrinkable"
|
|
395
|
+
${autoWidthSelect(input.uaText)}
|
|
396
|
+
title=${i18nString(UIStrings.deviceType)}
|
|
397
|
+
aria-label=${i18nString(UIStrings.deviceType)}
|
|
398
|
+
@change=${input.onUAChange}
|
|
399
|
+
.value=${input.uaOptions.find(o => o.selected)?.value || ''}
|
|
400
|
+
jslog=${VisualLogging.dropDown().track({change: true}).context('device-type')}
|
|
401
|
+
?disabled=${!input.isResponsive}>
|
|
402
|
+
${input.uaOptions.map(o => html`<option value=${o.value} ?selected=${o.selected} jslog=${VisualLogging.item(o.jslogContext).track({click: true})}>${o.title}</option>`)}
|
|
403
|
+
</select>` : ''}
|
|
404
|
+
<select class="dark-text" ${widget(MobileThrottling.NetworkThrottlingSelector.NetworkThrottlingSelect, {
|
|
405
|
+
title: i18nString(UIStrings.throttling),
|
|
406
|
+
bindToGlobalConditions: true,
|
|
407
|
+
})}></select>
|
|
408
|
+
<select class="dark-text toolbar-has-dropdown-shrinkable" ${widget(
|
|
409
|
+
MobileThrottling.ThrottlingManager.SaveDataOverrideSelect)}></select>
|
|
410
|
+
|
|
411
|
+
<div class="device-mode-empty-toolbar-element"></div>
|
|
412
|
+
<devtools-button class="toolbar-button"
|
|
413
|
+
.data=${{variant: Buttons.Button.Variant.TOOLBAR, iconName: 'screen-rotation'} as Buttons.Button.ButtonData}
|
|
414
|
+
jslog=${VisualLogging.action('screen-rotation').track({click: true})}
|
|
415
|
+
@click=${input.onModeMenuClick}
|
|
416
|
+
.title=${input.modeButtonTitle}
|
|
417
|
+
.disabled=${input.modeButtonDisabled}>
|
|
418
|
+
</devtools-button>
|
|
419
|
+
|
|
420
|
+
<!-- Show dual screen toolbar -->
|
|
421
|
+
${input.showSpanButton ? html`
|
|
422
|
+
<devtools-button class="toolbar-button"
|
|
423
|
+
.data=${{variant: Buttons.Button.Variant.TOOLBAR, iconName: 'device-fold'} as Buttons.Button.ButtonData}
|
|
424
|
+
jslog=${VisualLogging.action('device-fold').track({click: true})}
|
|
425
|
+
.title=${i18nString(UIStrings.toggleDualscreenMode)}
|
|
426
|
+
@click=${input.onSpanClick}>
|
|
427
|
+
</devtools-button>` : ''}
|
|
428
|
+
|
|
429
|
+
<!-- Show posture toolbar menu for foldable devices. -->
|
|
430
|
+
<div class="device-mode-empty-toolbar-element"></div>
|
|
431
|
+
${input.showPostureItem ? html`
|
|
432
|
+
<select class="dark-text toolbar-has-dropdown-shrinkable"
|
|
433
|
+
${autoWidthSelect(input.postureText)}
|
|
434
|
+
title=${i18nString(UIStrings.devicePosture)}
|
|
435
|
+
aria-label=${i18nString(UIStrings.devicePosture)}
|
|
436
|
+
@change=${input.onPostureChange}
|
|
437
|
+
.value=${input.postureOptions.find(o => o.selected)?.value || ''}
|
|
438
|
+
jslog=${VisualLogging.dropDown().track({change: true}).context('device-posture')}>
|
|
439
|
+
${input.postureOptions.map(o => html`<option value=${o.value} ?selected=${o.selected} jslog=${VisualLogging.item(o.value.toLowerCase()).track({click: true})}>${o.title}</option>`)}
|
|
440
|
+
</select>` : ''}
|
|
441
|
+
</devtools-toolbar>
|
|
442
|
+
<devtools-toolbar class="device-mode-toolbar-options" wrappable>
|
|
443
|
+
<div class="device-mode-empty-toolbar-element"></div>
|
|
444
|
+
<devtools-button
|
|
445
|
+
.data=${{variant: Buttons.Button.Variant.TOOLBAR, iconName: 'dots-vertical', title: i18nString(UIStrings.moreOptions)} as Buttons.Button.ButtonData}
|
|
446
|
+
@click=${input.onMoreOptionsClick}
|
|
447
|
+
jslog=${VisualLogging.dropDown('more-options').track({click: true})}
|
|
448
|
+
></devtools-button></devtools-toolbar>
|
|
449
|
+
`, target, {container: {
|
|
450
|
+
classes: ['device-mode-toolbar'],
|
|
451
|
+
attributes: {jslog: `${VisualLogging.toolbar('device-mode').track({resize: true})}`,
|
|
452
|
+
}
|
|
453
|
+
}});
|
|
454
|
+
// clang-format on
|
|
455
|
+
};
|
|
456
|
+
|
|
195
457
|
export class DeviceModeToolbar extends UI.Widget.Widget {
|
|
196
458
|
private model: EmulationModel.DeviceModeModel.DeviceModeModel;
|
|
197
459
|
private readonly showMediaInspectorSetting: Common.Settings.Setting<boolean>;
|
|
@@ -203,16 +465,14 @@ export class DeviceModeToolbar extends UI.Widget.Widget {
|
|
|
203
465
|
private readonly lastMode: Map<EmulationModel.EmulatedDevices.EmulatedDevice, EmulationModel.EmulatedDevices.Mode>;
|
|
204
466
|
private readonly emulatedDevicesList: EmulationModel.EmulatedDevices.EmulatedDevicesList;
|
|
205
467
|
private readonly persistenceSetting: Common.Settings.Setting<{device: string, orientation: string, mode: string}>;
|
|
206
|
-
private
|
|
207
|
-
private optionsToolbar: UI.Toolbar.Toolbar;
|
|
208
|
-
readonly #itemWidthCache = new Map<string, string>();
|
|
209
|
-
#measuringElement: HTMLSelectElement|null = null;
|
|
468
|
+
private readonly view: View;
|
|
210
469
|
|
|
211
470
|
constructor(
|
|
212
471
|
model: EmulationModel.DeviceModeModel.DeviceModeModel,
|
|
213
|
-
showMediaInspectorSetting: Common.Settings.Setting<boolean>,
|
|
214
|
-
|
|
472
|
+
showMediaInspectorSetting: Common.Settings.Setting<boolean>, showRulersSetting: Common.Settings.Setting<boolean>,
|
|
473
|
+
view: View = DEFAULT_VIEW) {
|
|
215
474
|
super();
|
|
475
|
+
this.view = view;
|
|
216
476
|
this.model = model;
|
|
217
477
|
this.showMediaInspectorSetting = showMediaInspectorSetting;
|
|
218
478
|
this.showRulersSetting = showRulersSetting;
|
|
@@ -231,11 +491,6 @@ export class DeviceModeToolbar extends UI.Widget.Widget {
|
|
|
231
491
|
|
|
232
492
|
this.lastMode = new Map();
|
|
233
493
|
|
|
234
|
-
this.contentElement.classList.add('device-mode-toolbar');
|
|
235
|
-
this.contentElement.setAttribute('jslog', VisualLogging.toolbar('device-mode').track({resize: true}).toString());
|
|
236
|
-
this.mainToolbar = this.createMainToolbar();
|
|
237
|
-
this.optionsToolbar = this.createOptionsToolbar();
|
|
238
|
-
|
|
239
494
|
this.emulatedDevicesList = EmulationModel.EmulatedDevices.EmulatedDevicesList.instance();
|
|
240
495
|
this.emulatedDevicesList.addEventListener(
|
|
241
496
|
EmulationModel.EmulatedDevices.Events.CUSTOM_DEVICES_UPDATED, this.deviceListChanged, this);
|
|
@@ -251,50 +506,10 @@ export class DeviceModeToolbar extends UI.Widget.Widget {
|
|
|
251
506
|
this.model.deviceScaleFactorSetting().addChangeListener(this.requestUpdate, this);
|
|
252
507
|
this.model.addEventListener(EmulationModel.DeviceModeModel.Events.UPDATED, this.requestUpdate, this);
|
|
253
508
|
|
|
254
|
-
this.
|
|
509
|
+
this.performUpdate();
|
|
255
510
|
}
|
|
256
511
|
|
|
257
|
-
|
|
258
|
-
const element = document.createElement('div');
|
|
259
|
-
element.classList.add('device-mode-empty-toolbar-element');
|
|
260
|
-
return element;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
private createSizeInput(
|
|
264
|
-
title: string, jslogContext: string, value: string|undefined, disabled: boolean|undefined,
|
|
265
|
-
placeholder: string|undefined, onChange: (event: Event) => void): LitTemplate {
|
|
266
|
-
return html`
|
|
267
|
-
<input type="number"
|
|
268
|
-
max=${EmulationModel.DeviceModeModel.MaxDeviceSize}
|
|
269
|
-
min=${EmulationModel.DeviceModeModel.MinDeviceSize}
|
|
270
|
-
title=${title}
|
|
271
|
-
class="device-mode-size-input"
|
|
272
|
-
.disabled=${disabled ?? false}
|
|
273
|
-
jslog=${VisualLogging.textField().track({change: true}).context(jslogContext)}
|
|
274
|
-
.value=${value ?? ''}
|
|
275
|
-
placeholder=${ifDefined(placeholder)}
|
|
276
|
-
@change=${onChange}
|
|
277
|
-
@keydown=${(event: Event): void => {
|
|
278
|
-
const input = event.target as HTMLInputElement;
|
|
279
|
-
let modifiedValue = UI.UIUtils.modifiedFloatNumber(Number(input.value), event);
|
|
280
|
-
if (modifiedValue === null) {
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
modifiedValue = Math.min(modifiedValue, EmulationModel.DeviceModeModel.MaxDeviceSize);
|
|
284
|
-
modifiedValue = Math.max(modifiedValue, EmulationModel.DeviceModeModel.MinDeviceSize);
|
|
285
|
-
|
|
286
|
-
event.preventDefault();
|
|
287
|
-
input.value = String(modifiedValue);
|
|
288
|
-
input.dispatchEvent(new Event('change'));
|
|
289
|
-
}}>`;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
private createMainToolbar(): UI.Toolbar.Toolbar {
|
|
293
|
-
const mainToolbar = this.contentElement.createChild('devtools-toolbar', 'main-toolbar');
|
|
294
|
-
return mainToolbar as UI.Toolbar.Toolbar;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
private renderMainToolbar(): void {
|
|
512
|
+
override performUpdate(): void {
|
|
298
513
|
const isResponsive = this.model.type() === EmulationModel.DeviceModeModel.Type.Responsive;
|
|
299
514
|
const isFullHeight = isResponsive && this.model.isFullHeight();
|
|
300
515
|
const size = this.model.appliedDeviceSize();
|
|
@@ -303,6 +518,24 @@ export class DeviceModeToolbar extends UI.Widget.Widget {
|
|
|
303
518
|
const heightPlaceholder = String(size.height);
|
|
304
519
|
|
|
305
520
|
const device = this.model.device();
|
|
521
|
+
|
|
522
|
+
if (this.model.type() === EmulationModel.DeviceModeModel.Type.Device && device) {
|
|
523
|
+
this.lastMode.set(device, (this.model.mode() as EmulationModel.EmulatedDevices.Mode));
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
const value = this.persistenceSetting.get();
|
|
527
|
+
const currentMode = this.model.mode();
|
|
528
|
+
if (device) {
|
|
529
|
+
value.device = device.title;
|
|
530
|
+
value.orientation = currentMode ? currentMode.orientation : '';
|
|
531
|
+
value.mode = currentMode ? currentMode.title : '';
|
|
532
|
+
} else {
|
|
533
|
+
value.device = '';
|
|
534
|
+
value.orientation = '';
|
|
535
|
+
value.mode = '';
|
|
536
|
+
}
|
|
537
|
+
this.persistenceSetting.set(value);
|
|
538
|
+
|
|
306
539
|
let modeButtonTitle = i18nString(UIStrings.rotate);
|
|
307
540
|
let modeButtonDisabled = false;
|
|
308
541
|
if (this.model.isScreenOrientationLocked()) {
|
|
@@ -348,149 +581,64 @@ export class DeviceModeToolbar extends UI.Widget.Widget {
|
|
|
348
581
|
const uaText = uaOptions.find(o => o.selected)?.title || '';
|
|
349
582
|
const postureText = postureOptions.find(o => o.selected)?.title || '';
|
|
350
583
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
</option>
|
|
378
|
-
</select>`})}
|
|
379
|
-
|
|
380
|
-
${this.createSizeInput(i18nString(UIStrings.width), 'width', widthValue, !isResponsive, '', (event: Event) => {
|
|
584
|
+
const enabled = this.model.toolbarControlsEnabledSetting().get();
|
|
585
|
+
this.contentElement.classList.toggle('disabled', !enabled);
|
|
586
|
+
|
|
587
|
+
const input: ViewInput = {
|
|
588
|
+
isResponsive,
|
|
589
|
+
isFullHeight,
|
|
590
|
+
widthValue,
|
|
591
|
+
heightValue,
|
|
592
|
+
heightPlaceholder,
|
|
593
|
+
modeButtonTitle,
|
|
594
|
+
modeButtonDisabled,
|
|
595
|
+
showSpanButton,
|
|
596
|
+
showPostureItem,
|
|
597
|
+
deviceModeOptions,
|
|
598
|
+
scaleOptions,
|
|
599
|
+
dprOptions,
|
|
600
|
+
uaOptions,
|
|
601
|
+
postureOptions,
|
|
602
|
+
selectedDeviceOption,
|
|
603
|
+
deviceText,
|
|
604
|
+
scaleText,
|
|
605
|
+
dprText,
|
|
606
|
+
uaText,
|
|
607
|
+
postureText,
|
|
608
|
+
onDeviceChange: this.onDeviceChange.bind(this),
|
|
609
|
+
onWidthChange: (event: Event) => {
|
|
381
610
|
const width = Number((event.target as HTMLInputElement).value);
|
|
382
611
|
if (this.autoAdjustScaleSetting.get()) {
|
|
383
612
|
this.model.setWidthAndScaleToFit(width);
|
|
384
613
|
} else {
|
|
385
614
|
this.model.setWidth(width);
|
|
386
615
|
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
<div class="device-mode-x">×</div>
|
|
390
|
-
${this.createSizeInput(i18nString(UIStrings.heightLeaveEmptyForFull), 'height', heightValue, !isResponsive, heightPlaceholder, (event: Event) => {
|
|
616
|
+
},
|
|
617
|
+
onHeightChange: (event: Event) => {
|
|
391
618
|
const height = Number((event.target as HTMLInputElement).value);
|
|
392
619
|
if (this.autoAdjustScaleSetting.get()) {
|
|
393
620
|
this.model.setHeightAndScaleToFit(height);
|
|
394
621
|
} else {
|
|
395
622
|
this.model.setHeight(height);
|
|
396
623
|
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
${bindToSetting(this.autoAdjustScaleSetting)}>
|
|
414
|
-
</devtools-button>
|
|
415
|
-
|
|
416
|
-
<div class="device-mode-empty-toolbar-element"></div>
|
|
417
|
-
|
|
418
|
-
${this.showDeviceScaleFactorSetting.get() ? html`
|
|
419
|
-
${i18nTemplate(str_, UIStrings.dpr, {
|
|
420
|
-
PH1: html`
|
|
421
|
-
<select class="dark-text toolbar-has-dropdown-shrinkable"
|
|
422
|
-
style=${styleMap({width: this.calculateItemWidth(dprText)})}
|
|
423
|
-
title=${i18nString(UIStrings.devicePixelRatio)}
|
|
424
|
-
aria-label=${i18nString(UIStrings.devicePixelRatio)}
|
|
425
|
-
@change=${this.onDeviceScaleChange.bind(this)}
|
|
426
|
-
.value=${String(dprOptions.find(o => o.selected)?.value || '')}
|
|
427
|
-
jslog=${VisualLogging.dropDown().track({change: true}).context('device-pixel-ratio')}
|
|
428
|
-
?disabled=${!isResponsive}>
|
|
429
|
-
${dprOptions.map(o => html`<option value=${o.value} ?selected=${o.selected} jslog=${VisualLogging.item(o.jslogContext).track({click: true})}>${o.title}</option>`)}
|
|
430
|
-
</select>`
|
|
431
|
-
})}` : ''}
|
|
432
|
-
|
|
433
|
-
<div class="device-mode-empty-toolbar-element"></div>
|
|
434
|
-
${this.showUserAgentTypeSetting.get() ? html`
|
|
435
|
-
<select class="dark-text toolbar-has-dropdown-shrinkable"
|
|
436
|
-
style=${styleMap({width: this.calculateItemWidth(uaText)})}
|
|
437
|
-
title=${i18nString(UIStrings.deviceType)}
|
|
438
|
-
aria-label=${i18nString(UIStrings.deviceType)}
|
|
439
|
-
@change=${this.onUAChange.bind(this)}
|
|
440
|
-
.value=${uaOptions.find(o => o.selected)?.value || ''}
|
|
441
|
-
jslog=${VisualLogging.dropDown().track({change: true}).context('device-type')}
|
|
442
|
-
?disabled=${!isResponsive}>
|
|
443
|
-
${uaOptions.map(o => html`<option value=${o.value} ?selected=${o.selected} jslog=${VisualLogging.item(o.jslogContext).track({click: true})}>${o.title}</option>`)}
|
|
444
|
-
</select>` : ''}
|
|
445
|
-
<select class="dark-text" ${widget(MobileThrottling.NetworkThrottlingSelector.NetworkThrottlingSelect, {
|
|
446
|
-
title: i18nString(UIStrings.throttling),
|
|
447
|
-
bindToGlobalConditions: true,
|
|
448
|
-
})}></select>
|
|
449
|
-
<select class="dark-text toolbar-has-dropdown-shrinkable" ${widget(
|
|
450
|
-
MobileThrottling.ThrottlingManager.SaveDataOverrideSelect)}></select>
|
|
451
|
-
|
|
452
|
-
<div class="device-mode-empty-toolbar-element"></div>
|
|
453
|
-
<devtools-button class="toolbar-button"
|
|
454
|
-
.data=${{variant: Buttons.Button.Variant.TOOLBAR, iconName: 'screen-rotation',
|
|
455
|
-
disabled: modeButtonDisabled} as Buttons.Button.ButtonData}
|
|
456
|
-
jslog=${VisualLogging.action('screen-rotation').track({click: true})}
|
|
457
|
-
@click=${this.modeMenuClicked.bind(this)}
|
|
458
|
-
.title=${modeButtonTitle}>
|
|
459
|
-
</devtools-button>
|
|
460
|
-
|
|
461
|
-
<!-- Show dual screen toolbar -->
|
|
462
|
-
${showSpanButton ? html`
|
|
463
|
-
<devtools-button class="toolbar-button"
|
|
464
|
-
.data=${{variant: Buttons.Button.Variant.TOOLBAR, iconName: 'device-fold'} as Buttons.Button.ButtonData}
|
|
465
|
-
jslog=${VisualLogging.action('device-fold').track({click: true})}
|
|
466
|
-
.title=${i18nString(UIStrings.toggleDualscreenMode)}
|
|
467
|
-
@click=${this.spanClicked.bind(this)}>
|
|
468
|
-
</devtools-button>` : ''}
|
|
469
|
-
|
|
470
|
-
<!-- Show posture toolbar menu for foldable devices. -->
|
|
471
|
-
<div class="device-mode-empty-toolbar-element"></div>
|
|
472
|
-
${showPostureItem ? html`
|
|
473
|
-
<select class="dark-text toolbar-has-dropdown-shrinkable"
|
|
474
|
-
style=${styleMap({width: this.calculateItemWidth(postureText)})}
|
|
475
|
-
title=${i18nString(UIStrings.devicePosture)}
|
|
476
|
-
aria-label=${i18nString(UIStrings.devicePosture)}
|
|
477
|
-
@change=${this.onPostureChange.bind(this)}
|
|
478
|
-
.value=${postureOptions.find(o => o.selected)?.value || ''}
|
|
479
|
-
jslog=${VisualLogging.dropDown().track({change: true}).context('device-posture')}>
|
|
480
|
-
${postureOptions.map(o => html`<option value=${o.value} ?selected=${o.selected} jslog=${VisualLogging.item(o.value.toLowerCase()).track({click: true})}>${o.title}</option>`)}
|
|
481
|
-
</select>` : ''}`, this.mainToolbar, {host: this});
|
|
482
|
-
// clang-format on
|
|
483
|
-
}
|
|
624
|
+
},
|
|
625
|
+
onScaleChange: this.onScaleChange.bind(this),
|
|
626
|
+
onDeviceScaleChange: this.onDeviceScaleChange.bind(this),
|
|
627
|
+
onUAChange: this.onUAChange.bind(this),
|
|
628
|
+
onPostureChange: this.onPostureChange.bind(this),
|
|
629
|
+
onModeMenuClick: this.modeMenuClicked.bind(this),
|
|
630
|
+
onSpanClick: this.spanClicked.bind(this),
|
|
631
|
+
onMoreOptionsClick: (event: Event) => {
|
|
632
|
+
const contextMenu = new UI.ContextMenu.ContextMenu(event);
|
|
633
|
+
this.appendOptionsMenuItems(contextMenu);
|
|
634
|
+
void contextMenu.show();
|
|
635
|
+
},
|
|
636
|
+
autoAdjustScaleSetting: this.autoAdjustScaleSetting,
|
|
637
|
+
showDeviceScaleFactorSetting: this.showDeviceScaleFactorSetting,
|
|
638
|
+
showUserAgentTypeSetting: this.showUserAgentTypeSetting,
|
|
639
|
+
};
|
|
484
640
|
|
|
485
|
-
|
|
486
|
-
const optionsToolbar = this.contentElement.createChild('devtools-toolbar', 'device-mode-toolbar-options');
|
|
487
|
-
optionsToolbar.wrappable = true;
|
|
488
|
-
optionsToolbar.appendToolbarItem(new UI.Toolbar.ToolbarItem(this.createEmptyToolbarElement()));
|
|
489
|
-
const moreOptionsButton = new UI.Toolbar.ToolbarMenuButton(
|
|
490
|
-
this.appendOptionsMenuItems.bind(this), true, undefined, 'more-options', 'dots-vertical');
|
|
491
|
-
moreOptionsButton.setTitle(i18nString(UIStrings.moreOptions));
|
|
492
|
-
optionsToolbar.appendToolbarItem(moreOptionsButton);
|
|
493
|
-
return optionsToolbar;
|
|
641
|
+
this.view(input, {}, this.contentElement);
|
|
494
642
|
}
|
|
495
643
|
|
|
496
644
|
private getDevicePostureOptions(): Array<{title: string, value: string, selected: boolean}> {
|
|
@@ -873,35 +1021,6 @@ export class DeviceModeToolbar extends UI.Widget.Widget {
|
|
|
873
1021
|
return `${(this.model.scale() * 100).toFixed(0)}`;
|
|
874
1022
|
}
|
|
875
1023
|
|
|
876
|
-
override performUpdate(): void {
|
|
877
|
-
const enabled = this.model.toolbarControlsEnabledSetting().get();
|
|
878
|
-
this.mainToolbar.setEnabled(enabled);
|
|
879
|
-
this.optionsToolbar.setEnabled(enabled);
|
|
880
|
-
|
|
881
|
-
const device = this.model.device();
|
|
882
|
-
|
|
883
|
-
if (this.model.type() === EmulationModel.DeviceModeModel.Type.Device) {
|
|
884
|
-
this.lastMode.set(
|
|
885
|
-
(this.model.device() as EmulationModel.EmulatedDevices.EmulatedDevice),
|
|
886
|
-
(this.model.mode() as EmulationModel.EmulatedDevices.Mode));
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
const value = this.persistenceSetting.get();
|
|
890
|
-
const currentMode = this.model.mode();
|
|
891
|
-
if (device) {
|
|
892
|
-
value.device = device.title;
|
|
893
|
-
value.orientation = currentMode ? currentMode.orientation : '';
|
|
894
|
-
value.mode = currentMode ? currentMode.title : '';
|
|
895
|
-
} else {
|
|
896
|
-
value.device = '';
|
|
897
|
-
value.orientation = '';
|
|
898
|
-
value.mode = '';
|
|
899
|
-
}
|
|
900
|
-
this.persistenceSetting.set(value);
|
|
901
|
-
|
|
902
|
-
this.renderMainToolbar();
|
|
903
|
-
}
|
|
904
|
-
|
|
905
1024
|
restore(): void {
|
|
906
1025
|
for (const device of this.allDevices()) {
|
|
907
1026
|
if (device.title === this.persistenceSetting.get().device) {
|
|
@@ -918,36 +1037,4 @@ export class DeviceModeToolbar extends UI.Widget.Widget {
|
|
|
918
1037
|
|
|
919
1038
|
this.model.emulate(EmulationModel.DeviceModeModel.Type.Responsive, null, null);
|
|
920
1039
|
}
|
|
921
|
-
|
|
922
|
-
private calculateItemWidth(text: string): string {
|
|
923
|
-
if (!text) {
|
|
924
|
-
return '';
|
|
925
|
-
}
|
|
926
|
-
if (this.#itemWidthCache.has(text)) {
|
|
927
|
-
return this.#itemWidthCache.get(text) as string;
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
if (!this.#measuringElement) {
|
|
931
|
-
this.#measuringElement = document.createElement('select');
|
|
932
|
-
this.#measuringElement.className = 'dark-text toolbar-has-dropdown-shrinkable';
|
|
933
|
-
this.#measuringElement.style.width = 'fit-content';
|
|
934
|
-
this.#measuringElement.style.position = 'absolute';
|
|
935
|
-
this.#measuringElement.style.visibility = 'hidden';
|
|
936
|
-
this.#measuringElement.style.pointerEvents = 'none';
|
|
937
|
-
const dummyOption = document.createElement('option');
|
|
938
|
-
this.#measuringElement.appendChild(dummyOption);
|
|
939
|
-
this.contentElement.appendChild(this.#measuringElement);
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
const dummyOption = this.#measuringElement.options[0];
|
|
943
|
-
dummyOption.textContent = text;
|
|
944
|
-
|
|
945
|
-
const width = this.#measuringElement.offsetWidth;
|
|
946
|
-
|
|
947
|
-
const widthPx = width ? `${width}px` : '';
|
|
948
|
-
if (width > 0) {
|
|
949
|
-
this.#itemWidthCache.set(text, widthPx);
|
|
950
|
-
}
|
|
951
|
-
return widthPx;
|
|
952
|
-
}
|
|
953
1040
|
}
|