chrome-devtools-frontend 1.0.1017408 → 1.0.1018151
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/i18n/locales/en-US.json +3 -0
- package/front_end/core/i18n/locales/en-XL.json +3 -0
- package/front_end/core/sdk/DebuggerModel.ts +4 -0
- package/front_end/core/sdk/FrameManager.ts +36 -15
- package/front_end/core/sdk/ResourceTreeModel.ts +29 -6
- package/front_end/core/sdk/SourceMap.ts +3 -4
- package/front_end/models/issues_manager/DeprecationIssue.ts +5 -2
- package/front_end/panels/application/components/FrameDetailsView.ts +31 -5
- package/front_end/panels/performance_monitor/PerformanceMonitor.ts +7 -0
- package/front_end/ui/components/panel_feedback/PreviewToggle.ts +8 -1
- package/front_end/ui/components/panel_feedback/previewToggle.css +6 -0
- package/package.json +1 -1
@@ -3035,6 +3035,9 @@
|
|
3035
3035
|
"panels/application/components/FrameDetailsView.ts | creationStackTraceExplanation": {
|
3036
3036
|
"message": "This frame was created programmatically. The stack trace shows where this happened."
|
3037
3037
|
},
|
3038
|
+
"panels/application/components/FrameDetailsView.ts | creatorAdScript": {
|
3039
|
+
"message": "Creator Ad Script"
|
3040
|
+
},
|
3038
3041
|
"panels/application/components/FrameDetailsView.ts | crossoriginIsolated": {
|
3039
3042
|
"message": "Cross-Origin Isolated"
|
3040
3043
|
},
|
@@ -3035,6 +3035,9 @@
|
|
3035
3035
|
"panels/application/components/FrameDetailsView.ts | creationStackTraceExplanation": {
|
3036
3036
|
"message": "T̂h́îś f̂ŕâḿê ẃâś ĉŕêát̂éd̂ ṕr̂óĝŕâḿm̂át̂íĉál̂ĺŷ. T́ĥé stack trace ŝh́ôẃŝ ẃĥér̂é t̂h́îś ĥáp̂ṕêńêd́."
|
3037
3037
|
},
|
3038
|
+
"panels/application/components/FrameDetailsView.ts | creatorAdScript": {
|
3039
|
+
"message": "Ĉŕêát̂ór̂ Ád̂ Śĉŕîṕt̂"
|
3040
|
+
},
|
3038
3041
|
"panels/application/components/FrameDetailsView.ts | crossoriginIsolated": {
|
3039
3042
|
"message": "Ĉŕôśŝ-Ór̂íĝín̂ Íŝól̂át̂éd̂"
|
3040
3043
|
},
|
@@ -230,6 +230,10 @@ export class DebuggerModel extends SDKModel<EventTypes> {
|
|
230
230
|
return Boolean(this.#debuggerEnabledInternal);
|
231
231
|
}
|
232
232
|
|
233
|
+
debuggerId(): string|null {
|
234
|
+
return this.#debuggerId;
|
235
|
+
}
|
236
|
+
|
233
237
|
private async enableDebugger(): Promise<void> {
|
234
238
|
if (this.#debuggerEnabledInternal) {
|
235
239
|
return;
|
@@ -28,8 +28,12 @@ export class FrameManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
|
|
28
28
|
}>;
|
29
29
|
readonly #framesForTarget: Map<Protocol.Target.TargetID|'main', Set<Protocol.Page.FrameId>>;
|
30
30
|
#topFrame: ResourceTreeFrame|null;
|
31
|
-
#
|
32
|
-
|
31
|
+
#transferringFramesDataCache: Map<string, {
|
32
|
+
creationStackTrace?: Protocol.Runtime.StackTrace,
|
33
|
+
creationStackTraceTarget?: Target,
|
34
|
+
adScriptId?: Protocol.Runtime.ScriptId,
|
35
|
+
debuggerId?: Protocol.Runtime.UniqueDebuggerId,
|
36
|
+
}>;
|
33
37
|
#awaitedFrames: Map<string, {notInTarget?: Target, resolve: (frame: ResourceTreeFrame) => void}[]> = new Map();
|
34
38
|
|
35
39
|
constructor() {
|
@@ -46,7 +50,7 @@ export class FrameManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
|
|
46
50
|
this.#framesForTarget = new Map();
|
47
51
|
|
48
52
|
this.#topFrame = null;
|
49
|
-
this.#
|
53
|
+
this.#transferringFramesDataCache = new Map();
|
50
54
|
}
|
51
55
|
|
52
56
|
static instance({forceNew}: {
|
@@ -94,19 +98,30 @@ export class FrameManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
|
|
94
98
|
const frameData = this.#frames.get(frame.id);
|
95
99
|
// If the frame is already in the map, increase its count, otherwise add it to the map.
|
96
100
|
if (frameData) {
|
97
|
-
// In order to not lose
|
98
|
-
// an OOPIF transfer we need to copy
|
101
|
+
// In order to not lose the following attributes of a frame during
|
102
|
+
// an OOPIF transfer we need to copy them to the new frame
|
99
103
|
frame.setCreationStackTrace(frameData.frame.getCreationStackTraceData());
|
104
|
+
frame.setAdScriptId(frameData.frame.getAdScriptId());
|
105
|
+
frame.setDebuggerId(frameData.frame.getDebuggerId());
|
100
106
|
this.#frames.set(frame.id, {frame, count: frameData.count + 1});
|
101
107
|
} else {
|
102
108
|
// If the transferring frame's detached event is received before its frame added
|
103
|
-
// event in the new target, the
|
104
|
-
const
|
105
|
-
if (
|
106
|
-
frame.setCreationStackTrace(
|
109
|
+
// event in the new target, the frame's cached attributes are reassigned.
|
110
|
+
const cachedFrameAttributes = this.#transferringFramesDataCache.get(frame.id);
|
111
|
+
if (cachedFrameAttributes?.creationStackTrace && cachedFrameAttributes?.creationStackTraceTarget) {
|
112
|
+
frame.setCreationStackTrace({
|
113
|
+
creationStackTrace: cachedFrameAttributes.creationStackTrace,
|
114
|
+
creationStackTraceTarget: cachedFrameAttributes.creationStackTraceTarget,
|
115
|
+
});
|
116
|
+
}
|
117
|
+
if (cachedFrameAttributes?.adScriptId) {
|
118
|
+
frame.setAdScriptId(cachedFrameAttributes.adScriptId);
|
119
|
+
}
|
120
|
+
if (cachedFrameAttributes?.debuggerId) {
|
121
|
+
frame.setDebuggerId(cachedFrameAttributes.debuggerId);
|
107
122
|
}
|
108
123
|
this.#frames.set(frame.id, {frame, count: 1});
|
109
|
-
this.#
|
124
|
+
this.#transferringFramesDataCache.delete(frame.id);
|
110
125
|
}
|
111
126
|
this.resetTopFrame();
|
112
127
|
|
@@ -126,13 +141,19 @@ export class FrameManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes>
|
|
126
141
|
this.decreaseOrRemoveFrame(frame.id);
|
127
142
|
|
128
143
|
// If the transferring frame's detached event is received before its frame
|
129
|
-
// added event in the new target, we persist the frame
|
130
|
-
// so that later on the frame added event in the new target
|
144
|
+
// added event in the new target, we persist some attributes of the frame here
|
145
|
+
// so that later on the frame added event in the new target they can be reassigned.
|
131
146
|
if (isSwap && !this.#frames.get(frame.id)) {
|
132
147
|
const traceData = frame.getCreationStackTraceData();
|
133
|
-
|
134
|
-
|
135
|
-
|
148
|
+
const adScriptId = frame.getAdScriptId();
|
149
|
+
const debuggerId = frame.getDebuggerId();
|
150
|
+
const cachedFrameAttributes = {
|
151
|
+
...(traceData.creationStackTrace && {creationStackTrace: traceData.creationStackTrace}),
|
152
|
+
...(traceData.creationStackTrace && {creationStackTraceTarget: traceData.creationStackTraceTarget}),
|
153
|
+
...(adScriptId && {adScriptId}),
|
154
|
+
...(debuggerId && {debuggerId}),
|
155
|
+
};
|
156
|
+
this.#transferringFramesDataCache.set(frame.id, cachedFrameAttributes);
|
136
157
|
}
|
137
158
|
|
138
159
|
// Remove the frameId from the target's set of frameIds.
|
@@ -182,7 +182,7 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
182
182
|
|
183
183
|
frameAttached(
|
184
184
|
frameId: Protocol.Page.FrameId, parentFrameId: Protocol.Page.FrameId|null,
|
185
|
-
stackTrace?: Protocol.Runtime.StackTrace): ResourceTreeFrame|null {
|
185
|
+
stackTrace?: Protocol.Runtime.StackTrace, adScriptId?: Protocol.Page.AdScriptId): ResourceTreeFrame|null {
|
186
186
|
const sameTargetParentFrame = parentFrameId ? (this.framesInternal.get(parentFrameId) || null) : null;
|
187
187
|
// Do nothing unless cached resource tree is processed - it will overwrite everything.
|
188
188
|
if (!this.#cachedResourcesProcessed && sameTargetParentFrame) {
|
@@ -192,7 +192,8 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
192
192
|
return null;
|
193
193
|
}
|
194
194
|
|
195
|
-
const frame =
|
195
|
+
const frame =
|
196
|
+
new ResourceTreeFrame(this, sameTargetParentFrame, frameId, null, stackTrace || null, adScriptId || null);
|
196
197
|
if (parentFrameId && !sameTargetParentFrame) {
|
197
198
|
frame.crossTargetParentFrameId = parentFrameId;
|
198
199
|
}
|
@@ -348,7 +349,7 @@ export class ResourceTreeModel extends SDKModel<EventTypes> {
|
|
348
349
|
private addFramesRecursively(
|
349
350
|
sameTargetParentFrame: ResourceTreeFrame|null, frameTreePayload: Protocol.Page.FrameResourceTree): void {
|
350
351
|
const framePayload = frameTreePayload.frame;
|
351
|
-
const frame = new ResourceTreeFrame(this, sameTargetParentFrame, framePayload.id, framePayload, null);
|
352
|
+
const frame = new ResourceTreeFrame(this, sameTargetParentFrame, framePayload.id, framePayload, null, null);
|
352
353
|
if (!sameTargetParentFrame && framePayload.parentId) {
|
353
354
|
frame.crossTargetParentFrameId = framePayload.parentId;
|
354
355
|
}
|
@@ -681,6 +682,8 @@ export class ResourceTreeFrame {
|
|
681
682
|
#creationStackTrace: Protocol.Runtime.StackTrace|null;
|
682
683
|
#creationStackTraceTarget: Target|null;
|
683
684
|
#childFramesInternal: Set<ResourceTreeFrame>;
|
685
|
+
#adScriptId: Protocol.Runtime.ScriptId|null;
|
686
|
+
#debuggerId: Protocol.Runtime.UniqueDebuggerId|null;
|
684
687
|
resourcesMap: Map<Platform.DevToolsPath.UrlString, Resource>;
|
685
688
|
backForwardCacheDetails: {
|
686
689
|
restoredFromCache: boolean|undefined,
|
@@ -695,7 +698,8 @@ export class ResourceTreeFrame {
|
|
695
698
|
|
696
699
|
constructor(
|
697
700
|
model: ResourceTreeModel, parentFrame: ResourceTreeFrame|null, frameId: Protocol.Page.FrameId,
|
698
|
-
payload: Protocol.Page.Frame|null, creationStackTrace: Protocol.Runtime.StackTrace|null
|
701
|
+
payload: Protocol.Page.Frame|null, creationStackTrace: Protocol.Runtime.StackTrace|null,
|
702
|
+
adScriptId: Protocol.Page.AdScriptId|null) {
|
699
703
|
this.#model = model;
|
700
704
|
this.#sameTargetParentFrameInternal = parentFrame;
|
701
705
|
this.#idInternal = frameId;
|
@@ -717,6 +721,9 @@ export class ResourceTreeFrame {
|
|
717
721
|
this.#creationStackTrace = creationStackTrace;
|
718
722
|
this.#creationStackTraceTarget = null;
|
719
723
|
|
724
|
+
this.#adScriptId = adScriptId?.scriptId || null;
|
725
|
+
this.#debuggerId = adScriptId?.debuggerId || null;
|
726
|
+
|
720
727
|
this.#childFramesInternal = new Set();
|
721
728
|
|
722
729
|
this.resourcesMap = new Map();
|
@@ -801,6 +808,22 @@ export class ResourceTreeFrame {
|
|
801
808
|
return this.#domainAndRegistryInternal;
|
802
809
|
}
|
803
810
|
|
811
|
+
getAdScriptId(): Protocol.Runtime.ScriptId|null {
|
812
|
+
return this.#adScriptId;
|
813
|
+
}
|
814
|
+
|
815
|
+
setAdScriptId(adScriptId: Protocol.Runtime.ScriptId|null): void {
|
816
|
+
this.#adScriptId = adScriptId;
|
817
|
+
}
|
818
|
+
|
819
|
+
getDebuggerId(): Protocol.Runtime.UniqueDebuggerId|null {
|
820
|
+
return this.#debuggerId;
|
821
|
+
}
|
822
|
+
|
823
|
+
setDebuggerId(debuggerId: Protocol.Runtime.UniqueDebuggerId|null): void {
|
824
|
+
this.#debuggerId = debuggerId;
|
825
|
+
}
|
826
|
+
|
804
827
|
get securityOrigin(): string|null {
|
805
828
|
return this.#securityOriginInternal;
|
806
829
|
}
|
@@ -1087,8 +1110,8 @@ export class PageDispatcher implements ProtocolProxyApi.PageDispatcher {
|
|
1087
1110
|
this.#resourceTreeModel.dispatchEventToListeners(Events.LifecycleEvent, {frameId, name});
|
1088
1111
|
}
|
1089
1112
|
|
1090
|
-
frameAttached({frameId, parentFrameId, stack}: Protocol.Page.FrameAttachedEvent): void {
|
1091
|
-
this.#resourceTreeModel.frameAttached(frameId, parentFrameId, stack);
|
1113
|
+
frameAttached({frameId, parentFrameId, stack, adScriptId}: Protocol.Page.FrameAttachedEvent): void {
|
1114
|
+
this.#resourceTreeModel.frameAttached(frameId, parentFrameId, stack, adScriptId);
|
1092
1115
|
}
|
1093
1116
|
|
1094
1117
|
frameNavigated({frame, type}: Protocol.Page.FrameNavigatedEvent): void {
|
@@ -451,11 +451,10 @@ export class TextSourceMap implements SourceMap {
|
|
451
451
|
if (url === this.#compiledURLInternal && source) {
|
452
452
|
url = Common.ParsedURL.ParsedURL.concatenate(url, '? [sm]');
|
453
453
|
}
|
454
|
-
if (this.#sourceInfos.has(url)) {
|
455
|
-
continue;
|
456
|
-
}
|
457
|
-
this.#sourceInfos.set(url, new TextSourceMap.SourceInfo(source ?? null));
|
458
454
|
sourcesList.push(url);
|
455
|
+
if (!this.#sourceInfos.has(url)) {
|
456
|
+
this.#sourceInfos.set(url, new TextSourceMap.SourceInfo(source ?? null));
|
457
|
+
}
|
459
458
|
}
|
460
459
|
sourceMapToSourceList.set(sourceMap, sourcesList);
|
461
460
|
}
|
@@ -253,7 +253,8 @@ const UIStrings = {
|
|
253
253
|
*/
|
254
254
|
rtcpMuxPolicyNegotiate: 'The `rtcpMuxPolicy` option is deprecated and will be removed.',
|
255
255
|
/**
|
256
|
-
* @description
|
256
|
+
* @description A deprecation warning shown in the DevTools Issues tab. The placeholder is always the noun
|
257
|
+
* "SharedArrayBuffer" which refers to a JavaScript construct.
|
257
258
|
*/
|
258
259
|
sharedArrayBufferConstructedWithoutIsolation:
|
259
260
|
'`SharedArrayBuffer` will require cross-origin isolation. See https://developer.chrome.com/blog/enabling-shared-array-buffer/ for more details.',
|
@@ -265,7 +266,9 @@ const UIStrings = {
|
|
265
266
|
textToSpeech_DisallowedByAutoplay:
|
266
267
|
'`speechSynthesis.speak()` without user activation is deprecated and will be removed.',
|
267
268
|
/**
|
268
|
-
* @description
|
269
|
+
* @description A deprecation warning shown in the DevTools Issues tab. The placeholder is always the noun
|
270
|
+
* "SharedArrayBuffer" which refers to a JavaScript construct. "Extensions" refers to Chrome extensions. The warning is shown
|
271
|
+
* when Chrome Extensions attempt to use "SharedArrayBuffer"s under insecure circumstances.
|
269
272
|
*/
|
270
273
|
v8SharedArrayBufferConstructedInExtensionWithoutIsolation:
|
271
274
|
'Extensions should opt into cross-origin isolation to continue using `SharedArrayBuffer`. See https://developer.chrome.com/docs/extensions/mv3/cross-origin-isolation/.',
|
@@ -10,7 +10,7 @@ import * as Bindings from '../../../models/bindings/bindings.js';
|
|
10
10
|
import * as Common from '../../../core/common/common.js';
|
11
11
|
import * as i18n from '../../../core/i18n/i18n.js';
|
12
12
|
import * as NetworkForward from '../../../panels/network/forward/forward.js';
|
13
|
-
import
|
13
|
+
import * as Platform from '../../../core/platform/platform.js';
|
14
14
|
import * as Root from '../../../core/root/root.js';
|
15
15
|
import * as SDK from '../../../core/sdk/sdk.js';
|
16
16
|
import * as LitHtml from '../../../ui/lit-html/lit-html.js';
|
@@ -248,6 +248,10 @@ const UIStrings = {
|
|
248
248
|
*@description Label for subtitle of frame details view
|
249
249
|
*/
|
250
250
|
prerenderingStatus: 'Prerendering Status',
|
251
|
+
/**
|
252
|
+
*@description Label for a link to an ad script, which created the current iframe.
|
253
|
+
*/
|
254
|
+
creatorAdScript: 'Creator Ad Script',
|
251
255
|
};
|
252
256
|
const str_ = i18n.i18n.registerUIStrings('panels/application/components/FrameDetailsView.ts', UIStrings);
|
253
257
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
@@ -266,7 +270,10 @@ export class FrameDetailsView extends UI.ThrottledWidget.ThrottledWidget {
|
|
266
270
|
}
|
267
271
|
|
268
272
|
async doUpdate(): Promise<void> {
|
269
|
-
|
273
|
+
const debuggerId = this.#frame?.getDebuggerId();
|
274
|
+
const debuggerModel = debuggerId ? await SDK.DebuggerModel.DebuggerModel.modelForDebuggerId(debuggerId) : null;
|
275
|
+
const target = debuggerModel?.target();
|
276
|
+
this.#reportView.data = {frame: this.#frame, target};
|
270
277
|
}
|
271
278
|
}
|
272
279
|
|
@@ -274,16 +281,19 @@ const coordinator = Coordinator.RenderCoordinator.RenderCoordinator.instance();
|
|
274
281
|
|
275
282
|
export interface FrameDetailsReportViewData {
|
276
283
|
frame: SDK.ResourceTreeModel.ResourceTreeFrame;
|
284
|
+
target?: SDK.Target.Target;
|
277
285
|
}
|
278
286
|
|
279
287
|
export class FrameDetailsReportView extends HTMLElement {
|
280
288
|
static readonly litTagName = LitHtml.literal`devtools-resources-frame-details-view`;
|
281
289
|
readonly #shadow = this.attachShadow({mode: 'open'});
|
282
290
|
#frame?: SDK.ResourceTreeModel.ResourceTreeFrame;
|
291
|
+
#target?: SDK.Target.Target;
|
283
292
|
#protocolMonitorExperimentEnabled = false;
|
284
293
|
#permissionsPolicies: Promise<Protocol.Page.PermissionsPolicyFeatureState[]|null>|null = null;
|
285
294
|
#permissionsPolicySectionData: PermissionsPolicySectionData = {policies: [], showDetails: false};
|
286
295
|
#originTrialTreeView: OriginTrialTreeView = new OriginTrialTreeView();
|
296
|
+
#linkifier = new Components.Linkifier.Linkifier();
|
287
297
|
|
288
298
|
connectedCallback(): void {
|
289
299
|
this.#protocolMonitorExperimentEnabled = Root.Runtime.experiments.isEnabled('protocolMonitor');
|
@@ -292,6 +302,7 @@ export class FrameDetailsReportView extends HTMLElement {
|
|
292
302
|
|
293
303
|
set data(data: FrameDetailsReportViewData) {
|
294
304
|
this.#frame = data.frame;
|
305
|
+
this.#target = data.target;
|
295
306
|
if (!this.#permissionsPolicies && this.#frame) {
|
296
307
|
this.#permissionsPolicies = this.#frame.getPermissionsPolicyState();
|
297
308
|
}
|
@@ -573,14 +584,29 @@ export class FrameDetailsReportView extends HTMLElement {
|
|
573
584
|
for (const explanation of this.#frame.adFrameStatus()?.explanations || []) {
|
574
585
|
rows.push(LitHtml.html`<div>${this.#getAdFrameExplanationString(explanation)}</div>`);
|
575
586
|
}
|
587
|
+
|
588
|
+
const adScriptLinkElement = this.#target ?
|
589
|
+
this.#linkifier.linkifyScriptLocation(
|
590
|
+
this.#target, this.#frame.getAdScriptId(), Platform.DevToolsPath.EmptyUrlString, undefined, undefined) :
|
591
|
+
null;
|
592
|
+
|
593
|
+
// Disabled until https://crbug.com/1079231 is fixed.
|
594
|
+
// clang-format off
|
576
595
|
return LitHtml.html`
|
577
596
|
<${ReportView.ReportView.ReportKey.litTagName}>${i18nString(UIStrings.adStatus)}</${
|
578
597
|
ReportView.ReportView.ReportKey.litTagName}>
|
579
598
|
<${ReportView.ReportView.ReportValue.litTagName}>
|
580
|
-
|
581
|
-
|
599
|
+
<${ExpandableList.ExpandableList.ExpandableList.litTagName} .data=${
|
600
|
+
{rows} as ExpandableList.ExpandableList.ExpandableListData}></${
|
582
601
|
ExpandableList.ExpandableList.ExpandableList.litTagName}></${ReportView.ReportView.ReportValue.litTagName}>
|
583
|
-
|
602
|
+
${this.#target ? LitHtml.html`
|
603
|
+
<${ReportView.ReportView.ReportKey.litTagName}>${i18nString(UIStrings.creatorAdScript)}</${
|
604
|
+
ReportView.ReportView.ReportKey.litTagName}>
|
605
|
+
<${ReportView.ReportView.ReportValue.litTagName} class="ad-script-link">${adScriptLinkElement}</${
|
606
|
+
ReportView.ReportView.ReportValue.litTagName}>
|
607
|
+
` : LitHtml.nothing}
|
608
|
+
`;
|
609
|
+
// clang-format on
|
584
610
|
}
|
585
611
|
|
586
612
|
#renderIsolationSection(): LitHtml.LitTemplate {
|
@@ -116,6 +116,13 @@ export class PerformanceMonitorImpl extends UI.Widget.HBox implements
|
|
116
116
|
}
|
117
117
|
this.registerCSSFiles([performanceMonitorStyles]);
|
118
118
|
this.controlPane.instantiateMetricData();
|
119
|
+
const themeSupport = ThemeSupport.ThemeSupport.instance();
|
120
|
+
themeSupport.addEventListener(ThemeSupport.ThemeChangeEvent.eventName, () => {
|
121
|
+
// instantiateMetricData sets the colors for the metrics, which we need
|
122
|
+
// to re-evaluate when the theme changes before re-drawing the canvas.
|
123
|
+
this.controlPane.instantiateMetricData();
|
124
|
+
this.draw();
|
125
|
+
});
|
119
126
|
SDK.TargetManager.TargetManager.instance().addEventListener(
|
120
127
|
SDK.TargetManager.Events.SuspendStateChanged, this.suspendStateChanged, this);
|
121
128
|
void this.model.enable();
|
@@ -67,11 +67,18 @@ export class PreviewToggle extends HTMLElement {
|
|
67
67
|
|
68
68
|
#render(): void {
|
69
69
|
const checked = Root.Runtime.experiments.isEnabled(this.#experiment);
|
70
|
+
const hasLink = Boolean(this.#feedbackURL) || Boolean(this.#learnMoreURL);
|
71
|
+
|
72
|
+
const containerClasses = LitHtml.Directives.classMap({
|
73
|
+
'container': true,
|
74
|
+
'has-link': hasLink,
|
75
|
+
});
|
76
|
+
|
70
77
|
// Disabled until https://crbug.com/1079231 is fixed.
|
71
78
|
// clang-format off
|
72
79
|
render(
|
73
80
|
html`
|
74
|
-
<div class
|
81
|
+
<div class=${containerClasses}>
|
75
82
|
<div class="checkbox-line">
|
76
83
|
<label class="experiment-preview">
|
77
84
|
<input type="checkbox" ?checked=${checked} @change=${this.#checkboxChanged} aria-label=${this.#name}/>
|
@@ -33,6 +33,12 @@
|
|
33
33
|
padding: 4px;
|
34
34
|
}
|
35
35
|
|
36
|
+
.container.has-link {
|
37
|
+
/* For x-link outline not to paint over the helper text
|
38
|
+
we need to have 2 * <padding>px additional line height */
|
39
|
+
line-height: calc(1em + 8px);
|
40
|
+
}
|
41
|
+
|
36
42
|
.x-link {
|
37
43
|
color: var(--color-primary);
|
38
44
|
text-decoration-line: underline;
|
package/package.json
CHANGED