chrome-devtools-frontend 1.0.1703574 → 1.0.1705227

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.
Files changed (85) hide show
  1. package/AUTHORS +2 -0
  2. package/docs/architecture_of_devtools.md +1 -1
  3. package/docs/cookbook/localization.md +2 -2
  4. package/front_end/core/common/ParsedURL.ts +54 -0
  5. package/front_end/core/common/README.md +4 -3
  6. package/front_end/core/platform/StringUtilities.ts +65 -0
  7. package/front_end/core/sdk/CPUThrottlingManager.ts +3 -3
  8. package/front_end/core/sdk/SourceMap.ts +3 -3
  9. package/front_end/core/sdk/SourceMapScopeChainEntry.ts +4 -3
  10. package/front_end/core/sdk/SourceMapScopesInfo.ts +17 -5
  11. package/front_end/entrypoints/formatter_actions/formatter_actions.ts +18 -0
  12. package/front_end/entrypoints/formatter_worker/Substitute.ts +9 -8
  13. package/front_end/entrypoints/formatter_worker/formatter_worker-entrypoint.ts +2 -2
  14. package/front_end/entrypoints/main/MainImpl.ts +3 -3
  15. package/front_end/foundation/Universe.ts +9 -0
  16. package/front_end/generated/InspectorBackendCommands.ts +3 -2
  17. package/front_end/generated/protocol.ts +16 -0
  18. package/front_end/models/bindings/CompilerScriptMapping.ts +1 -1
  19. package/front_end/models/formatter/FormatterWorkerPool.ts +8 -3
  20. package/front_end/models/har/HARFormat.ts +7 -2
  21. package/front_end/models/source_map_scopes/NamesResolver.ts +75 -38
  22. package/front_end/models/source_map_scopes/ScopeChainModel.ts +13 -45
  23. package/front_end/models/source_map_scopes/ScopeChainResolver.ts +101 -0
  24. package/front_end/models/source_map_scopes/source_map_scopes.ts +2 -0
  25. package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingListView.ts +33 -1
  26. package/front_end/panels/accessibility/AccessibilityAnnouncementRecordingView.ts +4 -12
  27. package/front_end/panels/application/ApplicationPanelSidebar.ts +58 -60
  28. package/front_end/panels/application/BackForwardCacheTreeElement.ts +1 -1
  29. package/front_end/panels/application/FrameDetailsView.ts +64 -82
  30. package/front_end/panels/application/OpenedWindowDetailsView.ts +20 -21
  31. package/front_end/panels/application/PreloadingTreeElement.ts +3 -3
  32. package/front_end/panels/common/CommentsOverlayWidget.ts +145 -72
  33. package/front_end/panels/common/commentsOverlay.css +34 -23
  34. package/front_end/panels/console/ConsolePrompt.ts +2 -1
  35. package/front_end/panels/elements/DOMTreeWidget.ts +29 -10
  36. package/front_end/panels/network/RequestPayloadView.ts +7 -2
  37. package/front_end/panels/network/ShowMoreDetailsWidget.ts +12 -9
  38. package/front_end/panels/sources/DebuggerPlugin.ts +52 -20
  39. package/front_end/panels/sources/ScopeChainSidebarPane.ts +2 -2
  40. package/front_end/panels/sources/SourcesPanel.ts +1 -1
  41. package/front_end/panels/sources/SourcesView.ts +3 -12
  42. package/front_end/panels/sources/TabbedEditorContainer.ts +0 -3
  43. package/front_end/panels/sources/components/HeadersView.ts +193 -123
  44. package/front_end/third_party/chromium/README.chromium +1 -1
  45. package/front_end/third_party/puppeteer/README.chromium +2 -2
  46. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +5 -0
  47. package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +24 -32
  48. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/ElementHandle.d.ts +1 -1
  49. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/ElementHandle.d.ts.map +1 -1
  50. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/ElementHandle.js +15 -1
  51. package/front_end/third_party/puppeteer/package/lib/puppeteer/api/ElementHandle.js.map +1 -1
  52. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Accessibility.js +8 -1
  53. package/front_end/third_party/puppeteer/package/lib/puppeteer/cdp/Accessibility.js.map +1 -1
  54. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts +0 -8
  55. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.d.ts.map +1 -1
  56. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js +0 -24
  57. package/front_end/third_party/puppeteer/package/lib/puppeteer/common/Debug.js.map +1 -1
  58. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.d.ts +12 -0
  59. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.d.ts.map +1 -1
  60. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.js +79 -17
  61. package/front_end/third_party/puppeteer/package/lib/puppeteer/node/BrowserLauncher.js.map +1 -1
  62. package/front_end/third_party/puppeteer/package/lib/puppeteer/node-env-setup.js +1 -1
  63. package/front_end/third_party/puppeteer/package/lib/puppeteer/node-env-setup.js.map +1 -1
  64. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.d.ts +3 -3
  65. package/front_end/third_party/puppeteer/package/lib/puppeteer/revisions.js +3 -3
  66. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.d.ts +1 -1
  67. package/front_end/third_party/puppeteer/package/lib/puppeteer/util/version.js +1 -1
  68. package/front_end/third_party/puppeteer/package/lib/types.d.ts +5 -0
  69. package/front_end/third_party/puppeteer/package/package.json +4 -4
  70. package/front_end/third_party/puppeteer/package/src/api/ElementHandle.ts +15 -2
  71. package/front_end/third_party/puppeteer/package/src/cdp/Accessibility.ts +10 -1
  72. package/front_end/third_party/puppeteer/package/src/common/Debug.ts +0 -27
  73. package/front_end/third_party/puppeteer/package/src/node/BrowserLauncher.ts +96 -17
  74. package/front_end/third_party/puppeteer/package/src/node-env-setup.ts +1 -1
  75. package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
  76. package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
  77. package/front_end/ui/comments/CommentAnchorResolver.ts +60 -22
  78. package/front_end/ui/comments/CommentOverlayManager.ts +78 -25
  79. package/front_end/ui/legacy/README.md +12 -12
  80. package/front_end/ui/legacy/components/data_grid/DataGridExporter.ts +7 -13
  81. package/front_end/ui/legacy/components/inline_editor/PositionAreaEditor.ts +51 -57
  82. package/front_end/ui/legacy/components/source_frame/ImageView.ts +101 -42
  83. package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -2
  84. package/front_end/ui/visual_logging/KnownContextValues.ts +7 -0
  85. package/package.json +1 -1
@@ -73,11 +73,11 @@ UI.ActionRegistration.registerActionExtension({
73
73
  bindings: [
74
74
  {
75
75
  shortcut: 'Ctrl+E',
76
- platform: UI.ActionRegistration.Platforms.WindowsLinux,
76
+ platform: UI.ActionRegistration.Platforms.WINDOWS_LINUX,
77
77
  },
78
78
  {
79
79
  shortcut: 'Meta+E',
80
- platform: UI.ActionRegistration.Platforms.Mac,
80
+ platform: UI.ActionRegistration.Platforms.MAC,
81
81
  },
82
82
  ],
83
83
  });
@@ -87,7 +87,7 @@ UI.ActionRegistration.registerActionExtension({
87
87
 
88
88
  #### Context types
89
89
  The `contextTypes` property determines the context under which the action is available.
90
- A context is defined as set 'flavors' or classes, which usually represent views, that are added and removed to the context as the user interacts with the application (e.g when the user moves across views).
90
+ A context is defined as set of 'flavors' or classes, which usually represent views, that are added and removed to the context as the user interacts with the application (e.g when the user moves across views).
91
91
  (See [`UI.Context`](./Context.js)).
92
92
  Therefore, an action can only be triggered when one of its respective context types is visible.
93
93
  These flavors can be retrieved invoking the method `flavors` inside the class `UI.Context.Context`.
@@ -97,10 +97,10 @@ In this case, the action will always be available, regardless of which context i
97
97
 
98
98
  #### Key bindings
99
99
 
100
- The `bindings` property defines a `platform` and a `keybindSets` properties along with the keyboard shortcut itself.
100
+ The `bindings` property defines `platform` and `keybindSets` properties along with the `shortcut` property containing the actual keyboard shortcut.
101
101
  These two extra properties add more conditions (additional to the ones introduced by the `contextTypes` property discussed before) that need to be fulfilled to trigger a particular action.
102
102
 
103
- - `platform` refers to the OS on which DevTools is running and can be either `mac` or `windows,linux`.
103
+ - `platform` refers to the OS on which DevTools is running and can be either `MAC`, `WINDOWS_LINUX` or `WINDOWS`. (See [`UI.ActionRegistration`](./ActionRegistration.ts)).
104
104
  - `keybindSets` refers to the selected shortcut preset, which can be changed in `settings -> shortcuts -> “Match shortcuts from preset”`.
105
105
  A key binding will be used when the selected preset matches any of the keybind sets declared by the binding.
106
106
 
@@ -125,16 +125,16 @@ UI.ActionRegistration.registerActionExtension({
125
125
  contextTypes: undefined,
126
126
  bindings: [
127
127
  {
128
- platform: 'windows,linux',
128
+ platform: UI.ActionRegistration.Platforms.WINDOWS_LINUX,
129
129
  shortcut: 'Esc',
130
130
  },
131
131
  ],
132
132
  });
133
133
  ```
134
134
 
135
- These two key bindings both allocate the same key for the `windows, linux` platform (the first one is global across platforms) in the `ElementsPanel` context (the second one is global across context types) and both are global across keybind sets.
135
+ These two key bindings both allocate the same key for the `WINDOWS_LINUX` platform (the first one is global across platforms) in the `ElementsPanel` context (the second one is global across context types) and both are global across keybind sets.
136
136
 
137
- If key bindings were declared such that **at least one** of the three variables (`platform, contextTypes` and `keybindSets`) doesn't overlap, then no duplication would occur.
137
+ If key bindings were declared such that **at least one** of the three variables (`platform`, `contextTypes` and `keybindSets`) doesn't overlap, then no duplication would occur.
138
138
  For example, the following is **not** a form of duplication:
139
139
 
140
140
  ```ts
@@ -147,7 +147,7 @@ UI.ActionRegistration.registerActionExtension({
147
147
  bindings: [
148
148
  {
149
149
  shortcut: 'Esc',
150
- keybindSets: ['devToolsDefault'],
150
+ keybindSets: [UI.ActionRegistration.KeybindSet.DEVTOOLS_DEFAULT],
151
151
  },
152
152
  ],
153
153
  });
@@ -160,12 +160,12 @@ UI.ActionRegistration.registerActionExtension({
160
160
  contextTypes: undefined,
161
161
  bindings: [
162
162
  {
163
- platform: 'windows,linux',
163
+ platform: UI.ActionRegistration.Platforms.WINDOWS_LINUX,
164
164
  shortcut: 'Esc',
165
- keybindSets: ['vsCode'],
165
+ keybindSets: [UI.ActionRegistration.KeybindSet.VS_CODE],
166
166
  },
167
167
  ],
168
168
  });
169
169
  ```
170
170
 
171
- In this case, they keybindings are declared for different keybind sets and thus do not result in duplcation.
171
+ In this case, the keybindings are declared for different keybind sets and thus do not result in duplication.
@@ -2,6 +2,8 @@
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
4
 
5
+ import * as Platform from '../../../../core/platform/platform.js';
6
+
5
7
  import type {DataGridImpl} from './DataGrid.js';
6
8
 
7
9
  /**
@@ -72,18 +74,10 @@ function escapeMarkdown(val: string): string {
72
74
  .replace(/\r?\n/g, '<br>');
73
75
  }
74
76
 
77
+ /**
78
+ * Escapes a string for CSV export (handling both RFC 4180 quoting and
79
+ * prefixing spreadsheet formula characters like `=`, `+`, `-`, `@` with `'`).
80
+ */
75
81
  function escapeCSV(val: string): string {
76
- let needQuotes = false;
77
- let escaped = val;
78
- if (escaped.includes('"')) {
79
- escaped = escaped.replace(/"/g, '""');
80
- needQuotes = true;
81
- }
82
- if (escaped.includes(',') || escaped.includes('\n') || escaped.includes('\r')) {
83
- needQuotes = true;
84
- }
85
- if (needQuotes) {
86
- return `"${escaped}"`;
87
- }
88
- return escaped;
82
+ return Platform.StringUtilities.escapeCsvCell(val);
89
83
  }
@@ -4,6 +4,7 @@
4
4
  import * as Common from '../../../../core/common/common.js';
5
5
  import * as i18n from '../../../../core/i18n/i18n.js';
6
6
  import * as Lit from '../../../../ui/lit/lit.js';
7
+ import * as VisualLogging from '../../../../ui/visual_logging/visual_logging.js';
7
8
  import * as UI from '../../legacy.js';
8
9
 
9
10
  import positionAreaEditorStyles from './positionAreaEditor.css.js';
@@ -19,21 +20,9 @@ const UIStrings = {
19
20
  */
20
21
  positionAreaGrid: 'position-area grid',
21
22
  /**
22
- * @description Title for the block axis section in the position-area editor.
23
+ * @description Title for the mode section and accessible label for the mode radio button group in the position-area editor.
23
24
  */
24
- block: 'Block',
25
- /**
26
- * @description Title for the inline axis section in the position-area editor.
27
- */
28
- inline: 'Inline',
29
- /**
30
- * @description Accessible label for the block axis mode radio button group.
31
- */
32
- blockAxisMode: 'Block axis mode',
33
- /**
34
- * @description Accessible label for the inline axis mode radio button group.
35
- */
36
- inlineAxisMode: 'Inline axis mode',
25
+ mode: 'Mode',
37
26
  /**
38
27
  * @description Label for physical mode radio button in the position-area editor.
39
28
  */
@@ -299,14 +288,15 @@ export interface ViewInput {
299
288
  onSelectStart: (x: number, y: number) => void;
300
289
  onSelect: (x: number, y: number) => void;
301
290
  onSelectEnd: (x?: number, y?: number) => void;
302
- onModeChange: (axis: Axis, mode: Mode) => void;
303
- onSelfChange: (axis: Axis, self: boolean) => void;
291
+ onModeChange: (mode: Mode) => void;
292
+ onSelfChange: (self: boolean) => void;
304
293
  }
305
294
  export type View = (input: ViewInput, output: undefined, target: HTMLElement) => void;
306
295
  export const DEFAULT_VIEW: View = (input, output, target) => {
307
296
  const container = {
308
297
  attributes: {
309
298
  tabindex: '0',
299
+ jslog: `${VisualLogging.dialog('position-area-editor').parent('mapped').track({keydown: 'Enter|Escape'})}`,
310
300
  },
311
301
  };
312
302
  if (!input.area) {
@@ -486,35 +476,42 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
486
476
 
487
477
  const blockAxis = input.area.primaryAxis === Axis.BLOCK ? input.area.first : input.area.second;
488
478
  const inlineAxis = input.area.primaryAxis === Axis.INLINE ? input.area.first : input.area.second;
479
+ const currentMode = blockAxis.mode === inlineAxis.mode ? blockAxis.mode : undefined;
480
+ const selfDisabled = (isGeneric(blockAxis) || blockAxis.mode === Mode.PHYSICAL) &&
481
+ (isGeneric(inlineAxis) || inlineAxis.mode === Mode.PHYSICAL);
482
+ const selfIndeterminate = !isGeneric(blockAxis) && !isGeneric(inlineAxis) && blockAxis.self !== inlineAxis.self;
483
+ const selfChecked = !selfIndeterminate && (blockAxis.self || inlineAxis.self);
489
484
 
490
- function renderModeRadioGroup(axis: Axis, currentMode: Mode): Lit.TemplateResult {
485
+ function renderModeRadioGroup(currentMode: Mode|undefined): Lit.TemplateResult {
491
486
  const modes = [
492
487
  {mode: Mode.PHYSICAL, label: i18nString(UIStrings.physical)},
493
488
  {mode: Mode.COORDINATE, label: i18nString(UIStrings.coordinate)},
494
489
  {mode: Mode.LOGICAL, label: i18nString(UIStrings.logical)},
495
490
  {mode: Mode.AUTO, label: i18nString(UIStrings.auto)},
496
491
  ];
497
- const axisModeLabel =
498
- axis === Axis.BLOCK ? i18nString(UIStrings.blockAxisMode) : i18nString(UIStrings.inlineAxisMode);
499
492
 
493
+ // clang-format off
500
494
  return html`
501
- <fieldset class="chip-radio-group" aria-label=${axisModeLabel}>
495
+ <fieldset class="chip-radio-group" aria-label=${i18nString(UIStrings.mode)}>
502
496
  ${modes.map(({mode, label}) => {
503
- const id = `${axis}-mode-${mode}`;
504
- return html`
505
- <input
506
- type="radio"
507
- id=${id}
508
- name="${axis}-mode"
509
- value=${mode}
510
- .checked=${currentMode === mode}
511
- @change=${() => input.onModeChange(axis, mode)}
512
- >
513
- <label for=${id}>${label}</label>
514
- `;
515
- })}
516
- </fieldset>
517
- `;
497
+ const id = `mode-${mode}`;
498
+ return html`
499
+ <input
500
+ type="radio"
501
+ id=${id}
502
+ name="mode"
503
+ value=${mode}
504
+ .checked=${currentMode === mode}
505
+ @change=${() => input.onModeChange(mode)}
506
+ >
507
+ <label
508
+ for=${id}
509
+ jslog=${VisualLogging.toggle(mode).track({click: true})}
510
+ >${label}</label>
511
+ `;
512
+ })}
513
+ </fieldset>`;
514
+ // clang-format on
518
515
  }
519
516
 
520
517
  // clang-format off
@@ -531,6 +528,7 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
531
528
  aria-label=${i18nString(UIStrings.positionAreaGrid)}
532
529
  aria-description=${i18nString(UIStrings.positionAreaGridDescription)}
533
530
  aria-multiselectable="true"
531
+ jslog=${VisualLogging.canvas('position-area-grid').track({click: true, drag: true, keydown: 'ArrowUp|ArrowDown|ArrowLeft|ArrowRight|Enter|Space'})}
534
532
  data-x-start=${x.start} data-x-end=${x.end} data-y-start=${y.start} data-y-end=${y.end}
535
533
  @pointerdown=${onPointerDown}
536
534
  @pointermove=${onPointerMove}
@@ -558,27 +556,17 @@ export const DEFAULT_VIEW: View = (input, output, target) => {
558
556
  <div class=position-area-controls>
559
557
  <div class=axis-section>
560
558
  <div class=axis-header>
561
- <span class=axis-title>${i18nString(UIStrings.block)}</span>
562
- <devtools-checkbox
563
- .checked=${blockAxis.self}
564
- ?disabled=${isGeneric(blockAxis)}
565
- @change=${(e: Event) => input.onSelfChange(Axis.BLOCK, (e.target as UI.UIUtils.CheckboxLabel).checked)}>
566
- <span class="self-checkbox-label source-code">self</span>
567
- </devtools-checkbox>
568
- </div>
569
- ${renderModeRadioGroup(Axis.BLOCK, blockAxis.mode)}
570
- </div>
571
- <div class=axis-section>
572
- <div class=axis-header>
573
- <span class=axis-title>${i18nString(UIStrings.inline)}</span>
559
+ <span class=axis-title>${i18nString(UIStrings.mode)}</span>
574
560
  <devtools-checkbox
575
- .checked=${inlineAxis.self}
576
- ?disabled=${isGeneric(inlineAxis)}
577
- @change=${(e: Event) => input.onSelfChange(Axis.INLINE, (e.target as UI.UIUtils.CheckboxLabel).checked)}>
561
+ .checked=${selfChecked}
562
+ .indeterminate=${selfIndeterminate}
563
+ ?disabled=${selfDisabled}
564
+ jslog=${VisualLogging.toggle('self').track({change: true})}
565
+ @change=${(e: Event) => input.onSelfChange((e.target as UI.UIUtils.CheckboxLabel).checked)}>
578
566
  <span class="self-checkbox-label source-code">self</span>
579
567
  </devtools-checkbox>
580
568
  </div>
581
- ${renderModeRadioGroup(Axis.INLINE, inlineAxis.mode)}
569
+ ${renderModeRadioGroup(currentMode)}
582
570
  </div>
583
571
  </div>
584
572
  `,
@@ -725,10 +713,10 @@ export class PositionAreaEditor extends PositionAreaEditorBase {
725
713
  other.mode = mode === Mode.COORDINATE ? Mode.COORDINATE : (other.self ? Mode.COORDINATE : Mode.PHYSICAL);
726
714
  }
727
715
  } else {
716
+ const self = current.self || other.self;
717
+ current.self = !isGeneric(current) && self;
728
718
  other.mode = mode;
729
- if (!isGeneric(current)) {
730
- other.self = current.self;
731
- }
719
+ other.self = !isGeneric(other) && self;
732
720
  }
733
721
  } else {
734
722
  other.mode = mode;
@@ -779,8 +767,14 @@ export class PositionAreaEditor extends PositionAreaEditorBase {
779
767
  onSelectStart: this.#startSelection.bind(this),
780
768
  onSelect: this.#select.bind(this),
781
769
  onSelectEnd: this.#finishSelection.bind(this),
782
- onModeChange: this.#setAxisMode.bind(this),
783
- onSelfChange: this.#setAxisSelf.bind(this),
770
+ onModeChange: (mode: Mode) => {
771
+ this.#setAxisMode(Axis.BLOCK, mode);
772
+ this.#setAxisMode(Axis.INLINE, mode);
773
+ },
774
+ onSelfChange: (self: boolean) => {
775
+ this.#setAxisSelf(Axis.BLOCK, self);
776
+ this.#setAxisSelf(Axis.INLINE, self);
777
+ },
784
778
  },
785
779
  undefined, this.contentElement);
786
780
  }
@@ -1,7 +1,6 @@
1
1
  // Copyright 2021 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
4
 
6
5
  /*
7
6
  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
@@ -31,13 +30,15 @@
31
30
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
31
  */
33
32
 
33
+ import '../../../kit/kit.js';
34
+
34
35
  import * as Common from '../../../../core/common/common.js';
35
36
  import * as Host from '../../../../core/host/host.js';
36
37
  import * as i18n from '../../../../core/i18n/i18n.js';
37
38
  import * as Platform from '../../../../core/platform/platform.js';
38
39
  import * as TextUtils from '../../../../core/text_utils/text_utils.js';
39
40
  import * as Workspace from '../../../../models/workspace/workspace.js';
40
- import {createIcon} from '../../../kit/kit.js';
41
+ import {html, render} from '../../../lit/lit.js';
41
42
  import * as VisualLogging from '../../../visual_logging/visual_logging.js';
42
43
  import * as UI from '../../legacy.js';
43
44
 
@@ -90,6 +91,54 @@ const UIStrings = {
90
91
  } as const;
91
92
  const str_ = i18n.i18n.registerUIStrings('ui/legacy/components/source_frame/ImageView.ts', UIStrings);
92
93
  const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
94
+
95
+ export interface ViewInput {
96
+ url: Platform.DevToolsPath.UrlString;
97
+ imageSrc: string|null;
98
+ isUnavailable: boolean;
99
+ onImageLoad: (event: Event) => void;
100
+ onContextMenu: (event: Event) => void;
101
+ }
102
+
103
+ export type View = (input: ViewInput, output: undefined, target: HTMLElement) => void;
104
+
105
+ // clang-format off
106
+ export const DEFAULT_VIEW: View = (input, _output, target) => {
107
+ render(html`
108
+ <style>${imageViewStyles}</style>
109
+ <div class="image">
110
+ ${input.imageSrc ? html`
111
+ <img
112
+ class="resource-image-view"
113
+ src=${input.imageSrc}
114
+ alt=${i18nString(UIStrings.imageFromS, {PH1: input.url})}
115
+ @load=${input.onImageLoad}
116
+ @contextmenu=${{handleEvent: input.onContextMenu, capture: true}}
117
+ >` : html`
118
+ <img
119
+ class="resource-image-view"
120
+ alt=${i18nString(UIStrings.imageFromS, {PH1: input.url})}
121
+ hidden
122
+ >`}
123
+ <devtools-link
124
+ class="resource-image-unavailable ${input.isUnavailable ? '' : 'hidden'}"
125
+ href=${input.url}
126
+ >
127
+ <devtools-icon name="open-externally"></devtools-icon>
128
+ ${i18nString(UIStrings.thisImageIsTooBig)}
129
+ </devtools-link>
130
+ </div>
131
+ `, target, {
132
+ container: {
133
+ classes: ['image-view'],
134
+ attributes: {
135
+ tabindex: '-1',
136
+ },
137
+ },
138
+ });
139
+ };
140
+ // clang-format on
141
+
93
142
  export class ImageView extends UI.View.SimpleView {
94
143
  private url: Platform.DevToolsPath.UrlString;
95
144
  private parsedURL: Common.ParsedURL.ParsedURL;
@@ -100,47 +149,58 @@ export class ImageView extends UI.View.SimpleView {
100
149
  private readonly dimensionsLabel: UI.Toolbar.ToolbarText;
101
150
  private readonly aspectRatioLabel: UI.Toolbar.ToolbarText;
102
151
  private readonly mimeTypeLabel: UI.Toolbar.ToolbarText;
103
- private readonly container: HTMLElement;
104
- private imagePreviewElement: HTMLImageElement;
105
- private imageUnavailableElement: HTMLElement;
106
152
  private cachedContent?: TextUtils.ContentData.ContentData;
107
- constructor(mimeType: string, contentProvider: TextUtils.ContentProvider.ContentProvider) {
153
+ readonly #view: View;
154
+ #imageSrc: string|null = null;
155
+ #isUnavailable = false;
156
+ #loadResolve?: () => void;
157
+
158
+ constructor(mimeType: string, contentProvider: TextUtils.ContentProvider.ContentProvider, view: View = DEFAULT_VIEW) {
108
159
  super({
109
160
  title: i18nString(UIStrings.image),
110
161
  viewId: 'image',
111
162
  jslog: `${VisualLogging.pane('image-view')}`,
112
163
  });
113
- this.registerRequiredCSS(imageViewStyles);
114
- this.element.tabIndex = -1;
115
- this.element.classList.add('image-view');
164
+ this.#view = view;
116
165
  this.url = contentProvider.contentURL();
117
166
  this.parsedURL = new Common.ParsedURL.ParsedURL(this.url);
118
167
  this.contentProvider = contentProvider;
119
168
  this.uiSourceCode = contentProvider instanceof Workspace.UISourceCode.UISourceCode ? contentProvider : null;
120
169
  if (this.uiSourceCode) {
121
- this.uiSourceCode.addEventListener(
122
- Workspace.UISourceCode.Events.WorkingCopyCommitted, this.workingCopyCommitted, this);
123
- new UI.DropTarget.DropTarget(
124
- this.element, [UI.DropTarget.Type.ImageFile, UI.DropTarget.Type.URI], i18nString(UIStrings.dropImageFileHere),
125
- this.handleDrop.bind(this));
170
+ this.uiSourceCode.addEventListener(Workspace.UISourceCode.Events.WorkingCopyCommitted, this.workingCopyCommitted,
171
+ this);
172
+ new UI.DropTarget.DropTarget(this.element, [UI.DropTarget.Type.ImageFile, UI.DropTarget.Type.URI],
173
+ i18nString(UIStrings.dropImageFileHere), this.handleDrop.bind(this));
126
174
  }
127
175
  this.sizeLabel = new UI.Toolbar.ToolbarText();
128
176
  this.dimensionsLabel = new UI.Toolbar.ToolbarText();
129
177
  this.aspectRatioLabel = new UI.Toolbar.ToolbarText();
130
178
  this.mimeTypeLabel = new UI.Toolbar.ToolbarText(mimeType);
131
- this.container = this.element.createChild('div', 'image');
132
- this.imagePreviewElement = this.container.createChild('img', 'resource-image-view');
133
- this.imagePreviewElement.addEventListener('contextmenu', this.contextMenu.bind(this), true);
179
+ this.performUpdate();
180
+ }
134
181
 
135
- const link = document.createElement('devtools-link');
136
- link.setAttribute('href', this.url);
137
- link.classList.add('resource-image-unavailable', 'hidden');
138
- link.appendChild(createIcon('open-externally'));
139
- link.appendChild(document.createTextNode(i18nString(UIStrings.thisImageIsTooBig)));
140
- this.container.appendChild(link);
141
- this.imageUnavailableElement = link;
182
+ override performUpdate(): void {
183
+ this.#view(
184
+ {
185
+ url: this.url,
186
+ imageSrc: this.#imageSrc,
187
+ isUnavailable: this.#isUnavailable,
188
+ onImageLoad: this.#onImageLoad,
189
+ onContextMenu: this.contextMenu.bind(this),
190
+ },
191
+ undefined,
192
+ this.contentElement,
193
+ );
142
194
  }
143
195
 
196
+ #onImageLoad = (event: Event): void => {
197
+ const img = event.target as HTMLImageElement;
198
+ this.dimensionsLabel.setText(i18nString(UIStrings.dD, {PH1: img.naturalWidth, PH2: img.naturalHeight}));
199
+ this.aspectRatioLabel.setText(Platform.NumberUtilities.aspectRatio(img.naturalWidth, img.naturalHeight));
200
+ this.#loadResolve?.();
201
+ this.#loadResolve = undefined;
202
+ };
203
+
144
204
  override async toolbarItems(): Promise<UI.Toolbar.ToolbarItem[]> {
145
205
  await this.updateContentIfNeeded();
146
206
  return [
@@ -156,13 +216,14 @@ export class ImageView extends UI.View.SimpleView {
156
216
 
157
217
  override wasShown(): void {
158
218
  super.wasShown();
219
+ this.requestUpdate();
159
220
  void this.updateContentIfNeeded();
160
221
  }
161
222
 
162
223
  override disposeView(): void {
163
224
  if (this.uiSourceCode) {
164
- this.uiSourceCode.removeEventListener(
165
- Workspace.UISourceCode.Events.WorkingCopyCommitted, this.workingCopyCommitted, this);
225
+ this.uiSourceCode.removeEventListener(Workspace.UISourceCode.Events.WorkingCopyCommitted,
226
+ this.workingCopyCommitted, this);
166
227
  }
167
228
  }
168
229
 
@@ -179,37 +240,35 @@ export class ImageView extends UI.View.SimpleView {
179
240
  this.cachedContent = content;
180
241
  const imageSrc = content.asImagePreviewUrl();
181
242
  if (imageSrc === null) {
182
- this.imageUnavailableElement.classList.remove('hidden');
243
+ this.#isUnavailable = true;
244
+ this.#imageSrc = null;
245
+ this.performUpdate();
183
246
  return;
184
247
  }
185
- this.imageUnavailableElement.classList.add('hidden');
186
- const loadPromise = new Promise(x => {
187
- this.imagePreviewElement.onload = x;
248
+ this.#isUnavailable = false;
249
+ const loadPromise = new Promise<void>(resolve => {
250
+ this.#loadResolve = resolve;
188
251
  });
189
- this.imagePreviewElement.src = imageSrc;
190
- this.imagePreviewElement.alt = i18nString(UIStrings.imageFromS, {PH1: this.url});
252
+ this.#imageSrc = imageSrc;
191
253
  const size = content.isTextContent ? content.text.length : Platform.StringUtilities.base64ToSize(content.base64);
192
254
  this.sizeLabel.setText(i18n.ByteUtilities.bytesToString(size));
255
+ this.performUpdate();
193
256
  await loadPromise;
194
- this.dimensionsLabel.setText(i18nString(
195
- UIStrings.dD, {PH1: this.imagePreviewElement.naturalWidth, PH2: this.imagePreviewElement.naturalHeight}));
196
- this.aspectRatioLabel.setText(Platform.NumberUtilities.aspectRatio(
197
- this.imagePreviewElement.naturalWidth, this.imagePreviewElement.naturalHeight));
198
257
  }
199
258
 
200
259
  private contextMenu(event: Event): void {
201
260
  const contextMenu = new UI.ContextMenu.ContextMenu(event);
202
- const parsedSrc = new Common.ParsedURL.ParsedURL(this.imagePreviewElement.src);
261
+ const parsedSrc = new Common.ParsedURL.ParsedURL(this.#imageSrc ?? '');
203
262
  if (!this.parsedURL.isDataURL()) {
204
263
  contextMenu.clipboardSection().appendItem(i18nString(UIStrings.copyImageUrl), this.copyImageURL.bind(this), {
205
264
  jslogContext: 'image-view.copy-image-url',
206
265
  });
207
266
  }
208
267
  if (parsedSrc.isDataURL()) {
209
- contextMenu.clipboardSection().appendItem(
210
- i18nString(UIStrings.copyImageAsDataUri), this.copyImageAsDataURL.bind(this), {
211
- jslogContext: 'image-view.copy-image-as-data-url',
212
- });
268
+ contextMenu.clipboardSection().appendItem(i18nString(UIStrings.copyImageAsDataUri),
269
+ this.copyImageAsDataURL.bind(this), {
270
+ jslogContext: 'image-view.copy-image-as-data-url',
271
+ });
213
272
  }
214
273
 
215
274
  contextMenu.clipboardSection().appendItem(i18nString(UIStrings.openImageInNewTab), this.openInNewTab.bind(this), {
@@ -223,7 +282,7 @@ export class ImageView extends UI.View.SimpleView {
223
282
  }
224
283
 
225
284
  private copyImageAsDataURL(): void {
226
- Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(this.imagePreviewElement.src);
285
+ Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText(this.#imageSrc ?? '');
227
286
  }
228
287
 
229
288
  private copyImageURL(): void {
@@ -593,8 +593,7 @@ export class Linkifier extends Common.ObjectWrapper.ObjectWrapper<EventTypes> im
593
593
  const lineNumber = options.lineNumber;
594
594
  const columnNumber = options.columnNumber;
595
595
  const showColumnNumber = options.showColumnNumber;
596
- const isPrivileged = Common.ParsedURL.schemeIs(url, 'chrome:') || Common.ParsedURL.schemeIs(url, 'file:') ||
597
- Common.ParsedURL.schemeIs(url, 'devtools:');
596
+ const isPrivileged = Common.ParsedURL.isPrivilegedScheme(url);
598
597
  const preventClick = options.preventClick;
599
598
  const maxLength = options.maxLength || UI.UIUtils.MaxLengthForDisplayedURLs;
600
599
  const bypassURLTrimming = options.bypassURLTrimming;
@@ -1058,6 +1058,7 @@ export const knownContextValues: Set<string> = new Set([
1058
1058
  'cookies',
1059
1059
  'cookies-data',
1060
1060
  'cookies-for-frame',
1061
+ 'coordinate',
1061
1062
  'copy',
1062
1063
  'copy-ai-response',
1063
1064
  'copy-all-as-curl',
@@ -1089,12 +1090,14 @@ export const knownContextValues: Set<string> = new Set([
1089
1090
  'copy-css-declaration-as-js',
1090
1091
  'copy-declaration',
1091
1092
  'copy-element',
1093
+ 'copy-element-html',
1092
1094
  'copy-file-name',
1093
1095
  'copy-full-xpath',
1094
1096
  'copy-initiator-url',
1095
1097
  'copy-js-path',
1096
1098
  'copy-key',
1097
1099
  'copy-link-address',
1100
+ 'copy-message',
1098
1101
  'copy-object',
1099
1102
  'copy-outer-html',
1100
1103
  'copy-payload',
@@ -2716,6 +2719,7 @@ export const knownContextValues: Set<string> = new Set([
2716
2719
  'location',
2717
2720
  'location-dialog',
2718
2721
  'log-level',
2722
+ 'logical',
2719
2723
  'logpoint',
2720
2724
  'long',
2721
2725
  'long-interaction',
@@ -3203,6 +3207,7 @@ export const knownContextValues: Set<string> = new Set([
3203
3207
  'perspective',
3204
3208
  'perspective-origin',
3205
3209
  'phone',
3210
+ 'physical',
3206
3211
  'picture-in-picture',
3207
3212
  'pill',
3208
3213
  'ping',
@@ -3253,6 +3258,8 @@ export const knownContextValues: Set<string> = new Set([
3253
3258
  'position',
3254
3259
  'position-anchor',
3255
3260
  'position-area',
3261
+ 'position-area-editor',
3262
+ 'position-area-grid',
3256
3263
  'position-fallback',
3257
3264
  'position-try',
3258
3265
  'position-try-fallbacks',
package/package.json CHANGED
@@ -91,5 +91,5 @@
91
91
  "yargs": "18.1.0",
92
92
  "yargs-unparser": "2.0.0"
93
93
  },
94
- "version": "1.0.1703574"
94
+ "version": "1.0.1705227"
95
95
  }