chrome-devtools-frontend 1.0.930993 → 1.0.932348
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/config/gni/devtools_grd_files.gni +6 -2
- package/front_end/core/common/ParsedURL.ts +12 -10
- package/front_end/core/host/InspectorFrontendHostAPI.ts +8 -6
- package/front_end/core/i18n/locales/en-US.json +345 -12
- package/front_end/core/i18n/locales/en-XL.json +345 -12
- package/front_end/core/platform/DevToolsPath.ts +34 -0
- package/front_end/core/platform/platform.ts +2 -0
- package/front_end/core/protocol_client/NodeURL.ts +2 -1
- package/front_end/core/sdk/CSSStyleSheetHeader.ts +4 -2
- package/front_end/core/sdk/ChildTargetManager.ts +2 -0
- package/front_end/core/sdk/CompilerSourceMappingContentProvider.ts +4 -2
- package/front_end/core/sdk/DebuggerModel.ts +4 -3
- package/front_end/core/sdk/NetworkRequest.ts +3 -2
- package/front_end/core/sdk/Resource.ts +6 -5
- package/front_end/core/sdk/Script.ts +4 -2
- package/front_end/core/sdk/Target.ts +4 -0
- package/front_end/core/sdk/TracingModel.ts +8 -17
- package/front_end/entrypoint_template.html +1 -1
- package/front_end/entrypoints/formatter_worker/ESTreeWalker.ts +1 -1
- package/front_end/models/bindings/BreakpointManager.ts +6 -3
- package/front_end/models/bindings/ResourceMapping.ts +2 -1
- package/front_end/models/bindings/StylesSourceMapping.ts +2 -1
- package/front_end/models/emulation/DeviceModeModel.ts +1 -1
- package/front_end/models/persistence/IsolatedFileSystem.ts +9 -7
- package/front_end/models/persistence/IsolatedFileSystemManager.ts +8 -7
- package/front_end/models/persistence/PersistenceActions.ts +1 -1
- package/front_end/models/persistence/PlatformFileSystem.ts +4 -3
- package/front_end/models/text_utils/ContentProvider.ts +2 -1
- package/front_end/models/text_utils/StaticContentProvider.ts +4 -2
- package/front_end/models/workspace/UISourceCode.ts +3 -2
- package/front_end/panels/animation/AnimationGroupPreviewUI.ts +25 -25
- package/front_end/panels/animation/AnimationModel.ts +157 -156
- package/front_end/panels/animation/AnimationScreenshotPopover.ts +26 -26
- package/front_end/panels/animation/AnimationTimeline.ts +274 -260
- package/front_end/panels/animation/AnimationUI.ts +155 -145
- package/front_end/panels/application/BackForwardCacheStrings.ts +621 -0
- package/front_end/panels/application/BackForwardCacheView.ts +24 -8
- package/front_end/panels/application/ReportingApiReportsView.ts +3 -2
- package/front_end/panels/application/ReportingApiView.ts +1 -2
- package/front_end/panels/application/backForwardCacheView.css +10 -0
- package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +48 -40
- package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +37 -37
- package/front_end/panels/browser_debugger/ObjectEventListenersSidebarPane.ts +23 -19
- package/front_end/panels/browser_debugger/XHRBreakpointsSidebarPane.ts +56 -56
- package/front_end/panels/changes/ChangesView.ts +42 -225
- package/front_end/panels/changes/changes-legacy.ts +0 -2
- package/front_end/panels/changes/changes.ts +0 -6
- package/front_end/panels/changes/changesView.css +2 -69
- package/front_end/panels/changes/module.json +1 -1
- package/front_end/panels/console/ConsolePinPane.ts +80 -75
- package/front_end/panels/console/ConsoleView.ts +1 -9
- package/front_end/panels/console/consolePinPane.css +4 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +2 -1
- package/front_end/panels/security/mainView.css +2 -1
- package/front_end/panels/snippets/ScriptSnippetFileSystem.ts +2 -1
- package/front_end/panels/sources/NavigatorView.ts +5 -2
- package/front_end/panels/sources/SourcesPanel.ts +28 -1
- package/front_end/panels/sources/sources-meta.ts +1 -4
- package/front_end/third_party/codemirror.next/bundle.ts +6 -4
- package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/markdown.js +1 -1
- package/front_end/third_party/codemirror.next/codemirror.next.d.ts +30 -1
- package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
- package/front_end/third_party/codemirror.next/package.json +4 -3
- package/front_end/ui/components/buttons/Button.ts +22 -6
- package/front_end/ui/components/buttons/button.css +50 -4
- package/front_end/ui/components/diff_view/DiffView.ts +288 -0
- package/front_end/ui/components/diff_view/diffView.css +73 -0
- package/front_end/ui/components/diff_view/diff_view.ts +5 -0
- package/front_end/ui/components/docs/button/basic.html +28 -0
- package/front_end/ui/components/docs/button/basic.ts +43 -2
- package/front_end/ui/components/report_view/report.css +1 -0
- package/front_end/ui/components/text_editor/config.ts +34 -1
- package/front_end/ui/legacy/ForwardedInputEventHandler.ts +5 -3
- package/front_end/ui/legacy/components/color_picker/spectrum.css +2 -4
- package/front_end/ui/legacy/themeColors.css +4 -0
- package/package.json +1 -1
- package/scripts/build/generate_css_js_files.js +1 -0
- package/scripts/migration/class-fields/migrate.js +1 -3
- package/front_end/panels/changes/ChangesHighlighter.ts +0 -179
- package/front_end/panels/changes/ChangesTextEditor.ts +0 -96
|
@@ -87,64 +87,64 @@ const playbackRates = new WeakMap<HTMLElement, number>();
|
|
|
87
87
|
let animationTimelineInstance: AnimationTimeline;
|
|
88
88
|
|
|
89
89
|
export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManager.SDKModelObserver<AnimationModel> {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
90
|
+
#gridWrapper: HTMLElement;
|
|
91
|
+
#grid: Element;
|
|
92
|
+
#playbackRate: number;
|
|
93
|
+
#allPaused: boolean;
|
|
94
|
+
#animationsContainer: HTMLElement;
|
|
95
|
+
#playbackRateButtons!: HTMLElement[];
|
|
96
|
+
#previewContainer!: HTMLElement;
|
|
97
|
+
#timelineScrubber!: HTMLElement;
|
|
98
|
+
#currentTime!: HTMLElement;
|
|
99
|
+
#popoverHelper!: UI.PopoverHelper.PopoverHelper;
|
|
100
|
+
#clearButton!: UI.Toolbar.ToolbarButton;
|
|
101
|
+
#selectedGroup!: AnimationGroup|null;
|
|
102
|
+
#renderQueue!: AnimationUI[];
|
|
103
|
+
#defaultDuration: number;
|
|
104
|
+
#durationInternal: number;
|
|
105
|
+
#timelineControlsWidth: number;
|
|
106
|
+
readonly #nodesMap: Map<number, NodeUI>;
|
|
107
|
+
#uiAnimations: AnimationUI[];
|
|
108
|
+
#groupBuffer: AnimationGroup[];
|
|
109
|
+
readonly #previewMap: Map<AnimationGroup, AnimationGroupPreviewUI>;
|
|
110
|
+
readonly #symbol: symbol;
|
|
111
|
+
readonly #animationsMap: Map<string, AnimationImpl>;
|
|
112
|
+
#timelineScrubberLine?: HTMLElement;
|
|
113
|
+
#pauseButton?: UI.Toolbar.ToolbarToggle;
|
|
114
|
+
#controlButton?: UI.Toolbar.ToolbarToggle;
|
|
115
|
+
#controlState?: ControlState;
|
|
116
|
+
#redrawing?: boolean;
|
|
117
|
+
#cachedTimelineWidth?: number;
|
|
118
|
+
#cachedTimelineHeight?: number;
|
|
119
|
+
#scrubberPlayer?: Animation;
|
|
120
|
+
#gridOffsetLeft?: number;
|
|
121
|
+
#originalScrubberTime?: number|null;
|
|
122
|
+
#originalMousePosition?: number;
|
|
123
123
|
|
|
124
124
|
private constructor() {
|
|
125
125
|
super(true);
|
|
126
126
|
|
|
127
127
|
this.element.classList.add('animations-timeline');
|
|
128
128
|
|
|
129
|
-
this
|
|
130
|
-
this
|
|
129
|
+
this.#gridWrapper = this.contentElement.createChild('div', 'grid-overflow-wrapper');
|
|
130
|
+
this.#grid = UI.UIUtils.createSVGChild(this.#gridWrapper, 'svg', 'animation-timeline-grid');
|
|
131
131
|
|
|
132
|
-
this
|
|
133
|
-
this
|
|
132
|
+
this.#playbackRate = 1;
|
|
133
|
+
this.#allPaused = false;
|
|
134
134
|
this.createHeader();
|
|
135
|
-
this
|
|
135
|
+
this.#animationsContainer = this.contentElement.createChild('div', 'animation-timeline-rows');
|
|
136
136
|
const timelineHint = this.contentElement.createChild('div', 'animation-timeline-rows-hint');
|
|
137
137
|
timelineHint.textContent = i18nString(UIStrings.selectAnEffectAboveToInspectAnd);
|
|
138
138
|
|
|
139
|
-
/** @const */ this
|
|
140
|
-
this
|
|
141
|
-
/** @const */ this
|
|
142
|
-
this
|
|
143
|
-
this
|
|
144
|
-
this
|
|
145
|
-
this
|
|
146
|
-
this
|
|
147
|
-
this
|
|
139
|
+
/** @const */ this.#defaultDuration = 100;
|
|
140
|
+
this.#durationInternal = this.#defaultDuration;
|
|
141
|
+
/** @const */ this.#timelineControlsWidth = 150;
|
|
142
|
+
this.#nodesMap = new Map();
|
|
143
|
+
this.#uiAnimations = [];
|
|
144
|
+
this.#groupBuffer = [];
|
|
145
|
+
this.#previewMap = new Map();
|
|
146
|
+
this.#symbol = Symbol('animationTimeline');
|
|
147
|
+
this.#animationsMap = new Map();
|
|
148
148
|
SDK.TargetManager.TargetManager.instance().addModelListener(
|
|
149
149
|
SDK.DOMModel.DOMModel, SDK.DOMModel.Events.NodeRemoved, this.nodeRemoved, this);
|
|
150
150
|
SDK.TargetManager.TargetManager.instance().observeModels(AnimationModel, this);
|
|
@@ -158,6 +158,18 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
158
158
|
return animationTimelineInstance;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
get previewMap(): Map<AnimationGroup, AnimationGroupPreviewUI> {
|
|
162
|
+
return this.#previewMap;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
get uiAnimations(): AnimationUI[] {
|
|
166
|
+
return this.#uiAnimations;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
get groupBuffer(): AnimationGroup[] {
|
|
170
|
+
return this.#groupBuffer;
|
|
171
|
+
}
|
|
172
|
+
|
|
161
173
|
wasShown(): void {
|
|
162
174
|
for (const animationModel of SDK.TargetManager.TargetManager.instance().models(AnimationModel)) {
|
|
163
175
|
this.addEventListeners(animationModel);
|
|
@@ -170,8 +182,8 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
170
182
|
this.removeEventListeners(animationModel);
|
|
171
183
|
}
|
|
172
184
|
|
|
173
|
-
if (this
|
|
174
|
-
this
|
|
185
|
+
if (this.#popoverHelper) {
|
|
186
|
+
this.#popoverHelper.hidePopover();
|
|
175
187
|
}
|
|
176
188
|
}
|
|
177
189
|
|
|
@@ -197,33 +209,33 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
197
209
|
}
|
|
198
210
|
|
|
199
211
|
private nodeChanged(): void {
|
|
200
|
-
for (const nodeUI of this
|
|
212
|
+
for (const nodeUI of this.#nodesMap.values()) {
|
|
201
213
|
nodeUI.nodeChanged();
|
|
202
214
|
}
|
|
203
215
|
}
|
|
204
216
|
|
|
205
217
|
private createScrubber(): HTMLElement {
|
|
206
|
-
this
|
|
207
|
-
this
|
|
208
|
-
this
|
|
209
|
-
this
|
|
210
|
-
this
|
|
211
|
-
this
|
|
212
|
-
return this
|
|
218
|
+
this.#timelineScrubber = document.createElement('div');
|
|
219
|
+
this.#timelineScrubber.classList.add('animation-scrubber');
|
|
220
|
+
this.#timelineScrubber.classList.add('hidden');
|
|
221
|
+
this.#timelineScrubberLine = this.#timelineScrubber.createChild('div', 'animation-scrubber-line');
|
|
222
|
+
this.#timelineScrubberLine.createChild('div', 'animation-scrubber-head');
|
|
223
|
+
this.#timelineScrubber.createChild('div', 'animation-time-overlay');
|
|
224
|
+
return this.#timelineScrubber;
|
|
213
225
|
}
|
|
214
226
|
|
|
215
227
|
private createHeader(): HTMLElement {
|
|
216
228
|
const toolbarContainer = this.contentElement.createChild('div', 'animation-timeline-toolbar-container');
|
|
217
229
|
const topToolbar = new UI.Toolbar.Toolbar('animation-timeline-toolbar', toolbarContainer);
|
|
218
|
-
this
|
|
219
|
-
this
|
|
220
|
-
topToolbar.appendToolbarItem(this
|
|
230
|
+
this.#clearButton = new UI.Toolbar.ToolbarButton(i18nString(UIStrings.clearAll), 'largeicon-clear');
|
|
231
|
+
this.#clearButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, this.reset.bind(this));
|
|
232
|
+
topToolbar.appendToolbarItem(this.#clearButton);
|
|
221
233
|
topToolbar.appendSeparator();
|
|
222
234
|
|
|
223
|
-
this
|
|
235
|
+
this.#pauseButton =
|
|
224
236
|
new UI.Toolbar.ToolbarToggle(i18nString(UIStrings.pauseAll), 'largeicon-pause', 'largeicon-resume');
|
|
225
|
-
this
|
|
226
|
-
topToolbar.appendToolbarItem(this
|
|
237
|
+
this.#pauseButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, this.togglePauseAll.bind(this));
|
|
238
|
+
topToolbar.appendToolbarItem(this.#pauseButton);
|
|
227
239
|
|
|
228
240
|
const playbackRateControl = toolbarContainer.createChild('div', 'animation-playback-rate-control');
|
|
229
241
|
playbackRateControl.addEventListener('keydown', this.handlePlaybackRateControlKeyDown.bind(this));
|
|
@@ -231,7 +243,7 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
231
243
|
UI.ARIAUtils.setAccessibleName(playbackRateControl, i18nString(UIStrings.playbackRates));
|
|
232
244
|
|
|
233
245
|
/** @type {!Array<!HTMLElement>} */
|
|
234
|
-
this
|
|
246
|
+
this.#playbackRateButtons = [];
|
|
235
247
|
for (const playbackRate of GlobalPlaybackRates) {
|
|
236
248
|
const button = (playbackRateControl.createChild('button', 'animation-playback-rate-button') as HTMLElement);
|
|
237
249
|
button.textContent = playbackRate ? i18nString(UIStrings.playbackRatePlaceholder, {PH1: playbackRate * 100}) :
|
|
@@ -241,41 +253,41 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
241
253
|
UI.ARIAUtils.markAsOption(button);
|
|
242
254
|
UI.Tooltip.Tooltip.install(button, i18nString(UIStrings.setSpeedToS, {PH1: button.textContent}));
|
|
243
255
|
button.tabIndex = -1;
|
|
244
|
-
this
|
|
256
|
+
this.#playbackRateButtons.push(button);
|
|
245
257
|
}
|
|
246
258
|
this.updatePlaybackControls();
|
|
247
|
-
this
|
|
248
|
-
UI.ARIAUtils.markAsListBox(this
|
|
249
|
-
UI.ARIAUtils.setAccessibleName(this
|
|
250
|
-
this
|
|
251
|
-
this
|
|
252
|
-
this
|
|
259
|
+
this.#previewContainer = (this.contentElement.createChild('div', 'animation-timeline-buffer') as HTMLElement);
|
|
260
|
+
UI.ARIAUtils.markAsListBox(this.#previewContainer);
|
|
261
|
+
UI.ARIAUtils.setAccessibleName(this.#previewContainer, i18nString(UIStrings.animationPreviews));
|
|
262
|
+
this.#popoverHelper = new UI.PopoverHelper.PopoverHelper(this.#previewContainer, this.getPopoverRequest.bind(this));
|
|
263
|
+
this.#popoverHelper.setDisableOnClick(true);
|
|
264
|
+
this.#popoverHelper.setTimeout(0);
|
|
253
265
|
const emptyBufferHint = this.contentElement.createChild('div', 'animation-timeline-buffer-hint');
|
|
254
266
|
emptyBufferHint.textContent = i18nString(UIStrings.waitingForAnimations);
|
|
255
267
|
const container = this.contentElement.createChild('div', 'animation-timeline-header');
|
|
256
268
|
const controls = container.createChild('div', 'animation-controls');
|
|
257
|
-
this
|
|
269
|
+
this.#currentTime = (controls.createChild('div', 'animation-timeline-current-time monospace') as HTMLElement);
|
|
258
270
|
|
|
259
271
|
const toolbar = new UI.Toolbar.Toolbar('animation-controls-toolbar', controls);
|
|
260
|
-
this
|
|
272
|
+
this.#controlButton =
|
|
261
273
|
new UI.Toolbar.ToolbarToggle(i18nString(UIStrings.replayTimeline), 'largeicon-replay-animation');
|
|
262
|
-
this
|
|
263
|
-
this
|
|
264
|
-
this
|
|
265
|
-
toolbar.appendToolbarItem(this
|
|
274
|
+
this.#controlState = ControlState.Replay;
|
|
275
|
+
this.#controlButton.setToggled(true);
|
|
276
|
+
this.#controlButton.addEventListener(UI.Toolbar.ToolbarButton.Events.Click, this.controlButtonToggle.bind(this));
|
|
277
|
+
toolbar.appendToolbarItem(this.#controlButton);
|
|
266
278
|
|
|
267
279
|
const gridHeader = container.createChild('div', 'animation-grid-header');
|
|
268
280
|
UI.UIUtils.installDragHandle(
|
|
269
281
|
gridHeader, this.repositionScrubber.bind(this), this.scrubberDragMove.bind(this),
|
|
270
282
|
this.scrubberDragEnd.bind(this), 'text');
|
|
271
|
-
this
|
|
283
|
+
this.#gridWrapper.appendChild(this.createScrubber());
|
|
272
284
|
|
|
273
|
-
if (this
|
|
285
|
+
if (this.#timelineScrubberLine) {
|
|
274
286
|
UI.UIUtils.installDragHandle(
|
|
275
|
-
this
|
|
287
|
+
this.#timelineScrubberLine, this.scrubberDragStart.bind(this), this.scrubberDragMove.bind(this),
|
|
276
288
|
this.scrubberDragEnd.bind(this), 'col-resize');
|
|
277
289
|
}
|
|
278
|
-
this
|
|
290
|
+
this.#currentTime.textContent = '';
|
|
279
291
|
|
|
280
292
|
return container;
|
|
281
293
|
}
|
|
@@ -296,12 +308,12 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
296
308
|
|
|
297
309
|
private focusNextPlaybackRateButton(target: EventTarget|null, focusPrevious?: boolean): void {
|
|
298
310
|
const button = (target as HTMLElement);
|
|
299
|
-
const currentIndex = this
|
|
311
|
+
const currentIndex = this.#playbackRateButtons.indexOf(button);
|
|
300
312
|
const nextIndex = focusPrevious ? currentIndex - 1 : currentIndex + 1;
|
|
301
|
-
if (nextIndex < 0 || nextIndex >= this
|
|
313
|
+
if (nextIndex < 0 || nextIndex >= this.#playbackRateButtons.length) {
|
|
302
314
|
return;
|
|
303
315
|
}
|
|
304
|
-
const nextButton = this
|
|
316
|
+
const nextButton = this.#playbackRateButtons[nextIndex];
|
|
305
317
|
nextButton.tabIndex = 0;
|
|
306
318
|
nextButton.focus();
|
|
307
319
|
if (target) {
|
|
@@ -311,7 +323,7 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
311
323
|
|
|
312
324
|
private getPopoverRequest(event: Event): UI.PopoverHelper.PopoverRequest|null {
|
|
313
325
|
const element = (event.target as HTMLElement);
|
|
314
|
-
if (!element || !element.isDescendant(this
|
|
326
|
+
if (!element || !element.isDescendant(this.#previewContainer)) {
|
|
315
327
|
return null;
|
|
316
328
|
}
|
|
317
329
|
|
|
@@ -319,7 +331,7 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
319
331
|
box: element.boxInWindow(),
|
|
320
332
|
show: (popover: UI.GlassPane.GlassPane): Promise<boolean> => {
|
|
321
333
|
let animGroup;
|
|
322
|
-
for (const [group, previewUI] of this
|
|
334
|
+
for (const [group, previewUI] of this.#previewMap) {
|
|
323
335
|
if (previewUI.element === element.parentElement) {
|
|
324
336
|
animGroup = group;
|
|
325
337
|
}
|
|
@@ -354,41 +366,41 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
354
366
|
}
|
|
355
367
|
|
|
356
368
|
private togglePauseAll(): void {
|
|
357
|
-
this
|
|
358
|
-
if (this
|
|
359
|
-
this
|
|
369
|
+
this.#allPaused = !this.#allPaused;
|
|
370
|
+
if (this.#pauseButton) {
|
|
371
|
+
this.#pauseButton.setToggled(this.#allPaused);
|
|
360
372
|
}
|
|
361
|
-
this.setPlaybackRate(this
|
|
362
|
-
if (this
|
|
363
|
-
this
|
|
373
|
+
this.setPlaybackRate(this.#playbackRate);
|
|
374
|
+
if (this.#pauseButton) {
|
|
375
|
+
this.#pauseButton.setTitle(this.#allPaused ? i18nString(UIStrings.resumeAll) : i18nString(UIStrings.pauseAll));
|
|
364
376
|
}
|
|
365
377
|
}
|
|
366
378
|
|
|
367
379
|
private setPlaybackRate(playbackRate: number): void {
|
|
368
|
-
this
|
|
380
|
+
this.#playbackRate = playbackRate;
|
|
369
381
|
for (const animationModel of SDK.TargetManager.TargetManager.instance().models(AnimationModel)) {
|
|
370
|
-
animationModel.setPlaybackRate(this
|
|
382
|
+
animationModel.setPlaybackRate(this.#allPaused ? 0 : this.#playbackRate);
|
|
371
383
|
}
|
|
372
384
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.AnimationsPlaybackRateChanged);
|
|
373
|
-
if (this
|
|
374
|
-
this
|
|
385
|
+
if (this.#scrubberPlayer) {
|
|
386
|
+
this.#scrubberPlayer.playbackRate = this.effectivePlaybackRate();
|
|
375
387
|
}
|
|
376
388
|
|
|
377
389
|
this.updatePlaybackControls();
|
|
378
390
|
}
|
|
379
391
|
|
|
380
392
|
private updatePlaybackControls(): void {
|
|
381
|
-
for (const button of this
|
|
382
|
-
const selected = this
|
|
393
|
+
for (const button of this.#playbackRateButtons) {
|
|
394
|
+
const selected = this.#playbackRate === playbackRates.get(button);
|
|
383
395
|
button.classList.toggle('selected', selected);
|
|
384
396
|
button.tabIndex = selected ? 0 : -1;
|
|
385
397
|
}
|
|
386
398
|
}
|
|
387
399
|
|
|
388
400
|
private controlButtonToggle(): void {
|
|
389
|
-
if (this
|
|
401
|
+
if (this.#controlState === ControlState.Play) {
|
|
390
402
|
this.togglePause(false);
|
|
391
|
-
} else if (this
|
|
403
|
+
} else if (this.#controlState === ControlState.Replay) {
|
|
392
404
|
this.replay();
|
|
393
405
|
} else {
|
|
394
406
|
this.togglePause(true);
|
|
@@ -396,42 +408,42 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
396
408
|
}
|
|
397
409
|
|
|
398
410
|
private updateControlButton(): void {
|
|
399
|
-
if (!this
|
|
411
|
+
if (!this.#controlButton) {
|
|
400
412
|
return;
|
|
401
413
|
}
|
|
402
414
|
|
|
403
|
-
this
|
|
404
|
-
if (this
|
|
405
|
-
this
|
|
406
|
-
this
|
|
407
|
-
this
|
|
408
|
-
this
|
|
415
|
+
this.#controlButton.setEnabled(Boolean(this.#selectedGroup));
|
|
416
|
+
if (this.#selectedGroup && this.#selectedGroup.paused()) {
|
|
417
|
+
this.#controlState = ControlState.Play;
|
|
418
|
+
this.#controlButton.setToggled(true);
|
|
419
|
+
this.#controlButton.setTitle(i18nString(UIStrings.playTimeline));
|
|
420
|
+
this.#controlButton.setGlyph('largeicon-play-animation');
|
|
409
421
|
} else if (
|
|
410
|
-
!this
|
|
411
|
-
this
|
|
412
|
-
this
|
|
413
|
-
this
|
|
414
|
-
this
|
|
415
|
-
this
|
|
422
|
+
!this.#scrubberPlayer || !this.#scrubberPlayer.currentTime ||
|
|
423
|
+
this.#scrubberPlayer.currentTime >= this.duration()) {
|
|
424
|
+
this.#controlState = ControlState.Replay;
|
|
425
|
+
this.#controlButton.setToggled(true);
|
|
426
|
+
this.#controlButton.setTitle(i18nString(UIStrings.replayTimeline));
|
|
427
|
+
this.#controlButton.setGlyph('largeicon-replay-animation');
|
|
416
428
|
} else {
|
|
417
|
-
this
|
|
418
|
-
this
|
|
419
|
-
this
|
|
420
|
-
this
|
|
429
|
+
this.#controlState = ControlState.Pause;
|
|
430
|
+
this.#controlButton.setToggled(false);
|
|
431
|
+
this.#controlButton.setTitle(i18nString(UIStrings.pauseTimeline));
|
|
432
|
+
this.#controlButton.setGlyph('largeicon-pause-animation');
|
|
421
433
|
}
|
|
422
434
|
}
|
|
423
435
|
|
|
424
436
|
private effectivePlaybackRate(): number {
|
|
425
|
-
return (this
|
|
437
|
+
return (this.#allPaused || (this.#selectedGroup && this.#selectedGroup.paused())) ? 0 : this.#playbackRate;
|
|
426
438
|
}
|
|
427
439
|
|
|
428
440
|
private togglePause(pause: boolean): void {
|
|
429
|
-
if (this
|
|
430
|
-
this
|
|
441
|
+
if (this.#scrubberPlayer) {
|
|
442
|
+
this.#scrubberPlayer.playbackRate = this.effectivePlaybackRate();
|
|
431
443
|
}
|
|
432
|
-
if (this
|
|
433
|
-
this
|
|
434
|
-
const preview = this
|
|
444
|
+
if (this.#selectedGroup) {
|
|
445
|
+
this.#selectedGroup.togglePause(pause);
|
|
446
|
+
const preview = this.#previewMap.get(this.#selectedGroup);
|
|
435
447
|
if (preview) {
|
|
436
448
|
preview.element.classList.toggle('paused', pause);
|
|
437
449
|
}
|
|
@@ -440,54 +452,54 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
440
452
|
}
|
|
441
453
|
|
|
442
454
|
private replay(): void {
|
|
443
|
-
if (!this
|
|
455
|
+
if (!this.#selectedGroup) {
|
|
444
456
|
return;
|
|
445
457
|
}
|
|
446
|
-
this
|
|
458
|
+
this.#selectedGroup.seekTo(0);
|
|
447
459
|
this.animateTime(0);
|
|
448
460
|
this.updateControlButton();
|
|
449
461
|
}
|
|
450
462
|
|
|
451
463
|
duration(): number {
|
|
452
|
-
return this
|
|
464
|
+
return this.#durationInternal;
|
|
453
465
|
}
|
|
454
466
|
|
|
455
467
|
setDuration(duration: number): void {
|
|
456
|
-
this
|
|
468
|
+
this.#durationInternal = duration;
|
|
457
469
|
this.scheduleRedraw();
|
|
458
470
|
}
|
|
459
471
|
|
|
460
472
|
private clearTimeline(): void {
|
|
461
|
-
this
|
|
462
|
-
this
|
|
463
|
-
this
|
|
464
|
-
this
|
|
465
|
-
this
|
|
466
|
-
this
|
|
467
|
-
this
|
|
468
|
-
if (this
|
|
469
|
-
this
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
this
|
|
473
|
+
this.#uiAnimations = [];
|
|
474
|
+
this.#nodesMap.clear();
|
|
475
|
+
this.#animationsMap.clear();
|
|
476
|
+
this.#animationsContainer.removeChildren();
|
|
477
|
+
this.#durationInternal = this.#defaultDuration;
|
|
478
|
+
this.#timelineScrubber.classList.add('hidden');
|
|
479
|
+
this.#selectedGroup = null;
|
|
480
|
+
if (this.#scrubberPlayer) {
|
|
481
|
+
this.#scrubberPlayer.cancel();
|
|
482
|
+
}
|
|
483
|
+
this.#scrubberPlayer = undefined;
|
|
484
|
+
this.#currentTime.textContent = '';
|
|
473
485
|
this.updateControlButton();
|
|
474
486
|
}
|
|
475
487
|
|
|
476
488
|
private reset(): void {
|
|
477
489
|
this.clearTimeline();
|
|
478
|
-
if (this
|
|
490
|
+
if (this.#allPaused) {
|
|
479
491
|
this.togglePauseAll();
|
|
480
492
|
} else {
|
|
481
|
-
this.setPlaybackRate(this
|
|
493
|
+
this.setPlaybackRate(this.#playbackRate);
|
|
482
494
|
}
|
|
483
495
|
|
|
484
|
-
for (const group of this
|
|
496
|
+
for (const group of this.#groupBuffer) {
|
|
485
497
|
group.release();
|
|
486
498
|
}
|
|
487
|
-
this
|
|
488
|
-
this
|
|
489
|
-
this
|
|
490
|
-
this
|
|
499
|
+
this.#groupBuffer = [];
|
|
500
|
+
this.#previewMap.clear();
|
|
501
|
+
this.#previewContainer.removeChildren();
|
|
502
|
+
this.#popoverHelper.hidePopover();
|
|
491
503
|
this.renderGrid();
|
|
492
504
|
}
|
|
493
505
|
|
|
@@ -503,46 +515,46 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
503
515
|
return left.startTime() > right.startTime() ? 1 : -1;
|
|
504
516
|
}
|
|
505
517
|
|
|
506
|
-
const previewGroup = this
|
|
518
|
+
const previewGroup = this.#previewMap.get(group);
|
|
507
519
|
if (previewGroup) {
|
|
508
|
-
if (this
|
|
520
|
+
if (this.#selectedGroup === group) {
|
|
509
521
|
this.syncScrubber();
|
|
510
522
|
} else {
|
|
511
523
|
previewGroup.replay();
|
|
512
524
|
}
|
|
513
525
|
return;
|
|
514
526
|
}
|
|
515
|
-
this
|
|
527
|
+
this.#groupBuffer.sort(startTimeComparator);
|
|
516
528
|
// Discard oldest groups from buffer if necessary
|
|
517
529
|
const groupsToDiscard = [];
|
|
518
530
|
const bufferSize = this.width() / 50;
|
|
519
|
-
while (this
|
|
520
|
-
const toDiscard = this
|
|
531
|
+
while (this.#groupBuffer.length > bufferSize) {
|
|
532
|
+
const toDiscard = this.#groupBuffer.splice(this.#groupBuffer[0] === this.#selectedGroup ? 1 : 0, 1);
|
|
521
533
|
groupsToDiscard.push(toDiscard[0]);
|
|
522
534
|
}
|
|
523
535
|
for (const g of groupsToDiscard) {
|
|
524
|
-
const discardGroup = this
|
|
536
|
+
const discardGroup = this.#previewMap.get(g);
|
|
525
537
|
if (!discardGroup) {
|
|
526
538
|
continue;
|
|
527
539
|
}
|
|
528
540
|
discardGroup.element.remove();
|
|
529
|
-
this
|
|
541
|
+
this.#previewMap.delete(g);
|
|
530
542
|
g.release();
|
|
531
543
|
}
|
|
532
544
|
// Generate preview
|
|
533
545
|
const preview = new AnimationGroupPreviewUI(group);
|
|
534
|
-
this
|
|
535
|
-
this
|
|
536
|
-
this
|
|
546
|
+
this.#groupBuffer.push(group);
|
|
547
|
+
this.#previewMap.set(group, preview);
|
|
548
|
+
this.#previewContainer.appendChild(preview.element);
|
|
537
549
|
preview.removeButton().addEventListener('click', this.removeAnimationGroup.bind(this, group));
|
|
538
550
|
preview.element.addEventListener('click', this.selectAnimationGroup.bind(this, group));
|
|
539
551
|
preview.element.addEventListener('keydown', this.handleAnimationGroupKeyDown.bind(this, group));
|
|
540
552
|
UI.ARIAUtils.setAccessibleName(
|
|
541
|
-
preview.element, i18nString(UIStrings.animationPreviewS, {PH1: this
|
|
553
|
+
preview.element, i18nString(UIStrings.animationPreviewS, {PH1: this.#groupBuffer.indexOf(group) + 1}));
|
|
542
554
|
UI.ARIAUtils.markAsOption(preview.element);
|
|
543
555
|
|
|
544
|
-
if (this
|
|
545
|
-
const preview = this
|
|
556
|
+
if (this.#previewMap.size === 1) {
|
|
557
|
+
const preview = this.#previewMap.get(this.#groupBuffer[0]);
|
|
546
558
|
if (preview) {
|
|
547
559
|
preview.element.tabIndex = 0;
|
|
548
560
|
}
|
|
@@ -570,12 +582,12 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
570
582
|
}
|
|
571
583
|
|
|
572
584
|
private focusNextGroup(group: AnimationGroup, target: EventTarget|null, focusPrevious?: boolean): void {
|
|
573
|
-
const currentGroupIndex = this
|
|
585
|
+
const currentGroupIndex = this.#groupBuffer.indexOf(group);
|
|
574
586
|
const nextIndex = focusPrevious ? currentGroupIndex - 1 : currentGroupIndex + 1;
|
|
575
|
-
if (nextIndex < 0 || nextIndex >= this
|
|
587
|
+
if (nextIndex < 0 || nextIndex >= this.#groupBuffer.length) {
|
|
576
588
|
return;
|
|
577
589
|
}
|
|
578
|
-
const preview = this
|
|
590
|
+
const preview = this.#previewMap.get(this.#groupBuffer[nextIndex]);
|
|
579
591
|
if (preview) {
|
|
580
592
|
preview.element.tabIndex = 0;
|
|
581
593
|
preview.element.focus();
|
|
@@ -587,30 +599,30 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
587
599
|
}
|
|
588
600
|
|
|
589
601
|
private removeAnimationGroup(group: AnimationGroup, event: Event): void {
|
|
590
|
-
const currentGroupIndex = this
|
|
602
|
+
const currentGroupIndex = this.#groupBuffer.indexOf(group);
|
|
591
603
|
|
|
592
|
-
Platform.ArrayUtilities.removeElement(this
|
|
593
|
-
const previewGroup = this
|
|
604
|
+
Platform.ArrayUtilities.removeElement(this.#groupBuffer, group);
|
|
605
|
+
const previewGroup = this.#previewMap.get(group);
|
|
594
606
|
if (previewGroup) {
|
|
595
607
|
previewGroup.element.remove();
|
|
596
608
|
}
|
|
597
|
-
this
|
|
609
|
+
this.#previewMap.delete(group);
|
|
598
610
|
group.release();
|
|
599
611
|
event.consume(true);
|
|
600
612
|
|
|
601
|
-
if (this
|
|
613
|
+
if (this.#selectedGroup === group) {
|
|
602
614
|
this.clearTimeline();
|
|
603
615
|
this.renderGrid();
|
|
604
616
|
}
|
|
605
617
|
|
|
606
|
-
const groupLength = this
|
|
618
|
+
const groupLength = this.#groupBuffer.length;
|
|
607
619
|
if (groupLength === 0) {
|
|
608
|
-
(this
|
|
620
|
+
(this.#clearButton.element as HTMLElement).focus();
|
|
609
621
|
return;
|
|
610
622
|
}
|
|
611
|
-
const nextGroup = currentGroupIndex >= this
|
|
612
|
-
this
|
|
613
|
-
this
|
|
623
|
+
const nextGroup = currentGroupIndex >= this.#groupBuffer.length ?
|
|
624
|
+
this.#previewMap.get(this.#groupBuffer[this.#groupBuffer.length - 1]) :
|
|
625
|
+
this.#previewMap.get(this.#groupBuffer[currentGroupIndex]);
|
|
614
626
|
|
|
615
627
|
if (nextGroup) {
|
|
616
628
|
nextGroup.element.tabIndex = 0;
|
|
@@ -620,23 +632,23 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
620
632
|
|
|
621
633
|
private selectAnimationGroup(group: AnimationGroup): void {
|
|
622
634
|
function applySelectionClass(this: AnimationTimeline, ui: AnimationGroupPreviewUI, group: AnimationGroup): void {
|
|
623
|
-
ui.element.classList.toggle('selected', this
|
|
635
|
+
ui.element.classList.toggle('selected', this.#selectedGroup === group);
|
|
624
636
|
}
|
|
625
637
|
|
|
626
|
-
if (this
|
|
638
|
+
if (this.#selectedGroup === group) {
|
|
627
639
|
this.togglePause(false);
|
|
628
640
|
this.replay();
|
|
629
641
|
return;
|
|
630
642
|
}
|
|
631
643
|
this.clearTimeline();
|
|
632
|
-
this
|
|
633
|
-
this
|
|
644
|
+
this.#selectedGroup = group;
|
|
645
|
+
this.#previewMap.forEach(applySelectionClass, this);
|
|
634
646
|
this.setDuration(Math.max(500, group.finiteDuration() + 100));
|
|
635
647
|
for (const anim of group.animations()) {
|
|
636
648
|
this.addAnimation(anim);
|
|
637
649
|
}
|
|
638
650
|
this.scheduleRedraw();
|
|
639
|
-
this
|
|
651
|
+
this.#timelineScrubber.classList.remove('hidden');
|
|
640
652
|
this.togglePause(false);
|
|
641
653
|
this.replay();
|
|
642
654
|
}
|
|
@@ -650,17 +662,17 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
650
662
|
}
|
|
651
663
|
}
|
|
652
664
|
|
|
653
|
-
let nodeUI = this
|
|
665
|
+
let nodeUI = this.#nodesMap.get(animation.source().backendNodeId());
|
|
654
666
|
if (!nodeUI) {
|
|
655
667
|
nodeUI = new NodeUI(animation.source());
|
|
656
|
-
this
|
|
657
|
-
this
|
|
668
|
+
this.#animationsContainer.appendChild(nodeUI.element);
|
|
669
|
+
this.#nodesMap.set(animation.source().backendNodeId(), nodeUI);
|
|
658
670
|
}
|
|
659
671
|
const nodeRow = nodeUI.createNewRow();
|
|
660
672
|
const uiAnimation = new AnimationUI(animation, this, nodeRow);
|
|
661
673
|
animation.source().deferredNode().resolve(nodeResolved.bind(this));
|
|
662
|
-
this
|
|
663
|
-
this
|
|
674
|
+
this.#uiAnimations.push(uiAnimation);
|
|
675
|
+
this.#animationsMap.set(animation.id(), animation);
|
|
664
676
|
}
|
|
665
677
|
|
|
666
678
|
private nodeRemoved(
|
|
@@ -675,17 +687,17 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
675
687
|
private renderGrid(): void {
|
|
676
688
|
/** @const */ const gridSize = 250;
|
|
677
689
|
const gridWidth = (this.width() + 10).toString();
|
|
678
|
-
const gridHeight = ((this
|
|
679
|
-
|
|
680
|
-
this
|
|
681
|
-
this
|
|
682
|
-
this
|
|
683
|
-
this
|
|
684
|
-
this
|
|
685
|
-
this
|
|
690
|
+
const gridHeight = ((this.#cachedTimelineHeight || 0) + 30).toString();
|
|
691
|
+
|
|
692
|
+
this.#gridWrapper.style.width = gridWidth + 'px';
|
|
693
|
+
this.#gridWrapper.style.height = gridHeight.toString() + 'px';
|
|
694
|
+
this.#grid.setAttribute('width', gridWidth);
|
|
695
|
+
this.#grid.setAttribute('height', gridHeight.toString());
|
|
696
|
+
this.#grid.setAttribute('shape-rendering', 'crispEdges');
|
|
697
|
+
this.#grid.removeChildren();
|
|
686
698
|
let lastDraw: number|undefined = undefined;
|
|
687
699
|
for (let time = 0; time < this.duration(); time += gridSize) {
|
|
688
|
-
const line = UI.UIUtils.createSVGChild(this
|
|
700
|
+
const line = UI.UIUtils.createSVGChild(this.#grid, 'rect', 'animation-timeline-grid-line');
|
|
689
701
|
line.setAttribute('x', (time * this.pixelMsRatio() + 10).toString());
|
|
690
702
|
line.setAttribute('y', '23');
|
|
691
703
|
line.setAttribute('height', '100%');
|
|
@@ -695,7 +707,7 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
695
707
|
const gridWidth = time * this.pixelMsRatio();
|
|
696
708
|
if (lastDraw === undefined || gridWidth - lastDraw > 50) {
|
|
697
709
|
lastDraw = gridWidth;
|
|
698
|
-
const label = UI.UIUtils.createSVGChild(this
|
|
710
|
+
const label = UI.UIUtils.createSVGChild(this.#grid, 'text', 'animation-timeline-grid-label');
|
|
699
711
|
label.textContent = i18n.TimeUtilities.millisToString(time);
|
|
700
712
|
label.setAttribute('x', (gridWidth + 10).toString());
|
|
701
713
|
label.setAttribute('y', '16');
|
|
@@ -704,44 +716,44 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
704
716
|
}
|
|
705
717
|
|
|
706
718
|
scheduleRedraw(): void {
|
|
707
|
-
this
|
|
708
|
-
for (const ui of this
|
|
709
|
-
this
|
|
719
|
+
this.#renderQueue = [];
|
|
720
|
+
for (const ui of this.#uiAnimations) {
|
|
721
|
+
this.#renderQueue.push(ui);
|
|
710
722
|
}
|
|
711
|
-
if (this
|
|
723
|
+
if (this.#redrawing) {
|
|
712
724
|
return;
|
|
713
725
|
}
|
|
714
|
-
this
|
|
726
|
+
this.#redrawing = true;
|
|
715
727
|
this.renderGrid();
|
|
716
|
-
this
|
|
728
|
+
this.#animationsContainer.window().requestAnimationFrame(this.render.bind(this));
|
|
717
729
|
}
|
|
718
730
|
|
|
719
731
|
private render(timestamp?: number): void {
|
|
720
|
-
while (this
|
|
721
|
-
const animationUI = this
|
|
732
|
+
while (this.#renderQueue.length && (!timestamp || window.performance.now() - timestamp < 50)) {
|
|
733
|
+
const animationUI = this.#renderQueue.shift();
|
|
722
734
|
if (animationUI) {
|
|
723
735
|
animationUI.redraw();
|
|
724
736
|
}
|
|
725
737
|
}
|
|
726
|
-
if (this
|
|
727
|
-
this
|
|
738
|
+
if (this.#renderQueue.length) {
|
|
739
|
+
this.#animationsContainer.window().requestAnimationFrame(this.render.bind(this));
|
|
728
740
|
} else {
|
|
729
|
-
|
|
741
|
+
this.#redrawing = undefined;
|
|
730
742
|
}
|
|
731
743
|
}
|
|
732
744
|
|
|
733
745
|
onResize(): void {
|
|
734
|
-
this
|
|
735
|
-
this
|
|
746
|
+
this.#cachedTimelineWidth = Math.max(0, this.#animationsContainer.offsetWidth - this.#timelineControlsWidth) || 0;
|
|
747
|
+
this.#cachedTimelineHeight = this.#animationsContainer.offsetHeight;
|
|
736
748
|
this.scheduleRedraw();
|
|
737
|
-
if (this
|
|
749
|
+
if (this.#scrubberPlayer) {
|
|
738
750
|
this.syncScrubber();
|
|
739
751
|
}
|
|
740
|
-
|
|
752
|
+
this.#gridOffsetLeft = undefined;
|
|
741
753
|
}
|
|
742
754
|
|
|
743
755
|
width(): number {
|
|
744
|
-
return this
|
|
756
|
+
return this.#cachedTimelineWidth || 0;
|
|
745
757
|
}
|
|
746
758
|
|
|
747
759
|
private resizeWindow(animation: AnimationImpl): boolean {
|
|
@@ -750,31 +762,33 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
750
762
|
// This shows at most 3 iterations
|
|
751
763
|
const duration = animation.source().duration() * Math.min(2, animation.source().iterations());
|
|
752
764
|
const requiredDuration = animation.source().delay() + duration + animation.source().endDelay();
|
|
753
|
-
if (requiredDuration > this
|
|
765
|
+
if (requiredDuration > this.#durationInternal) {
|
|
754
766
|
resized = true;
|
|
755
|
-
this
|
|
767
|
+
this.#durationInternal = requiredDuration + 200;
|
|
756
768
|
}
|
|
757
769
|
return resized;
|
|
758
770
|
}
|
|
759
771
|
|
|
760
772
|
private syncScrubber(): void {
|
|
761
|
-
if (!this
|
|
773
|
+
if (!this.#selectedGroup) {
|
|
762
774
|
return;
|
|
763
775
|
}
|
|
764
|
-
this
|
|
776
|
+
this.#selectedGroup.currentTimePromise()
|
|
777
|
+
.then(this.animateTime.bind(this))
|
|
778
|
+
.then(this.updateControlButton.bind(this));
|
|
765
779
|
}
|
|
766
780
|
|
|
767
781
|
private animateTime(currentTime: number): void {
|
|
768
|
-
if (this
|
|
769
|
-
this
|
|
782
|
+
if (this.#scrubberPlayer) {
|
|
783
|
+
this.#scrubberPlayer.cancel();
|
|
770
784
|
}
|
|
771
785
|
|
|
772
|
-
this
|
|
786
|
+
this.#scrubberPlayer = this.#timelineScrubber.animate(
|
|
773
787
|
[{transform: 'translateX(0px)'}, {transform: 'translateX(' + this.width() + 'px)'}],
|
|
774
788
|
{duration: this.duration(), fill: 'forwards'});
|
|
775
|
-
this
|
|
776
|
-
this
|
|
777
|
-
this
|
|
789
|
+
this.#scrubberPlayer.playbackRate = this.effectivePlaybackRate();
|
|
790
|
+
this.#scrubberPlayer.onfinish = this.updateControlButton.bind(this);
|
|
791
|
+
this.#scrubberPlayer.currentTime = currentTime;
|
|
778
792
|
this.element.window().requestAnimationFrame(this.updateScrubber.bind(this));
|
|
779
793
|
}
|
|
780
794
|
|
|
@@ -783,50 +797,50 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
783
797
|
}
|
|
784
798
|
|
|
785
799
|
private updateScrubber(_timestamp: number): void {
|
|
786
|
-
if (!this
|
|
800
|
+
if (!this.#scrubberPlayer) {
|
|
787
801
|
return;
|
|
788
802
|
}
|
|
789
|
-
this
|
|
790
|
-
if (this
|
|
803
|
+
this.#currentTime.textContent = i18n.TimeUtilities.millisToString(this.#scrubberPlayer.currentTime || 0);
|
|
804
|
+
if (this.#scrubberPlayer.playState.toString() === 'pending' || this.#scrubberPlayer.playState === 'running') {
|
|
791
805
|
this.element.window().requestAnimationFrame(this.updateScrubber.bind(this));
|
|
792
|
-
} else if (this
|
|
793
|
-
this
|
|
806
|
+
} else if (this.#scrubberPlayer.playState === 'finished') {
|
|
807
|
+
this.#currentTime.textContent = '';
|
|
794
808
|
}
|
|
795
809
|
}
|
|
796
810
|
|
|
797
811
|
private repositionScrubber(event: Event): boolean {
|
|
798
|
-
if (!this
|
|
812
|
+
if (!this.#selectedGroup) {
|
|
799
813
|
return false;
|
|
800
814
|
}
|
|
801
815
|
|
|
802
816
|
// Seek to current mouse position.
|
|
803
|
-
if (!this
|
|
804
|
-
this
|
|
817
|
+
if (!this.#gridOffsetLeft) {
|
|
818
|
+
this.#gridOffsetLeft = this.#grid.totalOffsetLeft() + 10;
|
|
805
819
|
}
|
|
806
820
|
|
|
807
821
|
const {x} = (event as any); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
808
|
-
const seekTime = Math.max(0, x - this
|
|
809
|
-
this
|
|
822
|
+
const seekTime = Math.max(0, x - this.#gridOffsetLeft) / this.pixelMsRatio();
|
|
823
|
+
this.#selectedGroup.seekTo(seekTime);
|
|
810
824
|
this.togglePause(true);
|
|
811
825
|
this.animateTime(seekTime);
|
|
812
826
|
|
|
813
827
|
// Interface with scrubber drag.
|
|
814
|
-
this
|
|
815
|
-
this
|
|
828
|
+
this.#originalScrubberTime = seekTime;
|
|
829
|
+
this.#originalMousePosition = x;
|
|
816
830
|
return true;
|
|
817
831
|
}
|
|
818
832
|
|
|
819
833
|
private scrubberDragStart(event: Event): boolean {
|
|
820
|
-
if (!this
|
|
834
|
+
if (!this.#scrubberPlayer || !this.#selectedGroup) {
|
|
821
835
|
return false;
|
|
822
836
|
}
|
|
823
837
|
|
|
824
|
-
this
|
|
825
|
-
this
|
|
826
|
-
this
|
|
838
|
+
this.#originalScrubberTime = this.#scrubberPlayer.currentTime;
|
|
839
|
+
this.#timelineScrubber.classList.remove('animation-timeline-end');
|
|
840
|
+
this.#scrubberPlayer.pause();
|
|
827
841
|
|
|
828
842
|
const {x} = (event as any); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
829
|
-
this
|
|
843
|
+
this.#originalMousePosition = x;
|
|
830
844
|
|
|
831
845
|
this.togglePause(true);
|
|
832
846
|
return true;
|
|
@@ -834,26 +848,26 @@ export class AnimationTimeline extends UI.Widget.VBox implements SDK.TargetManag
|
|
|
834
848
|
|
|
835
849
|
private scrubberDragMove(event: Event): void {
|
|
836
850
|
const {x} = (event as any); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
837
|
-
const delta = x - (this
|
|
851
|
+
const delta = x - (this.#originalMousePosition || 0);
|
|
838
852
|
const currentTime =
|
|
839
|
-
Math.max(0, Math.min((this
|
|
840
|
-
if (this
|
|
841
|
-
this
|
|
853
|
+
Math.max(0, Math.min((this.#originalScrubberTime || 0) + delta / this.pixelMsRatio(), this.duration()));
|
|
854
|
+
if (this.#scrubberPlayer) {
|
|
855
|
+
this.#scrubberPlayer.currentTime = currentTime;
|
|
842
856
|
}
|
|
843
|
-
this
|
|
857
|
+
this.#currentTime.textContent = i18n.TimeUtilities.millisToString(Math.round(currentTime));
|
|
844
858
|
|
|
845
|
-
if (this
|
|
846
|
-
this
|
|
859
|
+
if (this.#selectedGroup) {
|
|
860
|
+
this.#selectedGroup.seekTo(currentTime);
|
|
847
861
|
}
|
|
848
862
|
}
|
|
849
863
|
|
|
850
864
|
private scrubberDragEnd(_event: Event): void {
|
|
851
|
-
if (this
|
|
852
|
-
const currentTime = Math.max(0, this
|
|
853
|
-
this
|
|
854
|
-
this
|
|
865
|
+
if (this.#scrubberPlayer) {
|
|
866
|
+
const currentTime = Math.max(0, this.#scrubberPlayer.currentTime || 0);
|
|
867
|
+
this.#scrubberPlayer.play();
|
|
868
|
+
this.#scrubberPlayer.currentTime = currentTime;
|
|
855
869
|
}
|
|
856
|
-
this
|
|
870
|
+
this.#currentTime.window().requestAnimationFrame(this.updateScrubber.bind(this));
|
|
857
871
|
}
|
|
858
872
|
}
|
|
859
873
|
|
|
@@ -867,44 +881,44 @@ const enum ControlState {
|
|
|
867
881
|
|
|
868
882
|
export class NodeUI {
|
|
869
883
|
element: HTMLDivElement;
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
884
|
+
readonly #description: HTMLElement;
|
|
885
|
+
readonly #timelineElement: HTMLElement;
|
|
886
|
+
#node?: SDK.DOMModel.DOMNode|null;
|
|
873
887
|
|
|
874
888
|
constructor(_animationEffect: AnimationEffect) {
|
|
875
889
|
this.element = document.createElement('div');
|
|
876
890
|
this.element.classList.add('animation-node-row');
|
|
877
|
-
this
|
|
878
|
-
this
|
|
879
|
-
UI.ARIAUtils.markAsApplication(this
|
|
891
|
+
this.#description = this.element.createChild('div', 'animation-node-description');
|
|
892
|
+
this.#timelineElement = this.element.createChild('div', 'animation-node-timeline');
|
|
893
|
+
UI.ARIAUtils.markAsApplication(this.#timelineElement);
|
|
880
894
|
}
|
|
881
895
|
|
|
882
896
|
nodeResolved(node: SDK.DOMModel.DOMNode|null): void {
|
|
883
897
|
if (!node) {
|
|
884
|
-
UI.UIUtils.createTextChild(this
|
|
898
|
+
UI.UIUtils.createTextChild(this.#description, '<node>');
|
|
885
899
|
return;
|
|
886
900
|
}
|
|
887
|
-
this
|
|
901
|
+
this.#node = node;
|
|
888
902
|
this.nodeChanged();
|
|
889
|
-
Common.Linkifier.Linkifier.linkify(node).then(link => this
|
|
903
|
+
Common.Linkifier.Linkifier.linkify(node).then(link => this.#description.appendChild(link));
|
|
890
904
|
if (!node.ownerDocument) {
|
|
891
905
|
this.nodeRemoved();
|
|
892
906
|
}
|
|
893
907
|
}
|
|
894
908
|
|
|
895
909
|
createNewRow(): Element {
|
|
896
|
-
return this
|
|
910
|
+
return this.#timelineElement.createChild('div', 'animation-timeline-row');
|
|
897
911
|
}
|
|
898
912
|
|
|
899
913
|
nodeRemoved(): void {
|
|
900
914
|
this.element.classList.add('animation-node-removed');
|
|
901
|
-
this
|
|
915
|
+
this.#node = null;
|
|
902
916
|
}
|
|
903
917
|
|
|
904
918
|
nodeChanged(): void {
|
|
905
919
|
let animationNodeSelected = false;
|
|
906
|
-
if (this
|
|
907
|
-
animationNodeSelected = (this
|
|
920
|
+
if (this.#node) {
|
|
921
|
+
animationNodeSelected = (this.#node === UI.Context.Context.instance().flavor(SDK.DOMModel.DOMNode));
|
|
908
922
|
}
|
|
909
923
|
|
|
910
924
|
this.element.classList.toggle('animation-node-selected', animationNodeSelected);
|