Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/front_end/timeline/TimelineLandingPage.js |
| diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineLandingPage.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineLandingPage.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a6c232755cccb197fd1042e8c4bd22c1dae33bda |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineLandingPage.js |
| @@ -0,0 +1,213 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +Timeline.Perspective = class { |
| + /** |
| + * @param {string} id |
| + * @param {string} title |
| + * @param {string} description |
| + * @param {!Array<string>=} visibleOptions |
| + */ |
| + constructor(id, title, description, visibleOptions) { |
| + this.id = id; |
| + this.title = title; |
| + this.description = description; |
| + /** @type {!Object<string, !Timeline.Perspective.Config>} */ |
| + this.settings = { |
|
caseq
2016/12/07 20:17:29
Why do we make the base class aware of all possibl
alph
2016/12/08 07:22:45
Done.
|
| + 'network': { |
| + value: false, |
| + title: Common.UIString('Network'), |
| + description: Common.UIString('Capture network requests information.'), |
| + setting: 'timelineCaptureNetwork' |
|
caseq
2016/12/07 20:17:29
I wonder whether we should better use actual insta
alph
2016/12/08 07:22:45
I want it to be a config template. No objects allo
|
| + }, |
| + 'javascript': { |
| + value: true, |
| + title: Common.UIString('JavaScript'), |
| + description: Common.UIString('Use sampling CPU profiler to collect JavaScript stacks.'), |
| + setting: 'timelineEnableJSSampling' |
| + }, |
| + 'screenshots': { |
| + value: false, |
| + title: Common.UIString('Screenshots'), |
| + description: |
| + Common.UIString('Collect page screenshots, so you can observe how the page was evolving during recording.'), |
| + setting: 'timelineCaptureFilmStrip' |
| + }, |
| + 'paints': { |
| + value: false, |
| + title: Common.UIString('Paints'), |
| + description: Common.UIString( |
| + 'Capture graphics layer positions and rasterization draw calls (moderate performance overhead).'), |
| + setting: 'timelineCaptureLayersAndPictures' |
| + }, |
| + 'memory': { |
| + value: true, |
| + title: Common.UIString('Memory'), |
| + description: Common.UIString('Capture memory information on every timeline event.'), |
| + setting: 'timelineCaptureMemory' |
| + }, |
| + 'reload': { |
| + value: false, |
| + title: Common.UIString('Auto Reload'), |
| + description: Common.UIString('Automatically reload page when recoring has started.') |
| + } |
| + }; |
| + this._visibleOptions = visibleOptions || []; |
| + } |
| + |
| + /** |
| + * @param {!Element} parent |
| + */ |
| + appendElements(parent) { |
| + for (let id of this._visibleOptions) { |
| + const config = this.settings[id]; |
| + this._createSettingCheckBox(parent, id, config); |
| + } |
| + } |
| + |
| + /** |
| + * @param {!Element} parent |
| + * @param {string} id |
| + * @param {!Timeline.Perspective.Config} config |
| + */ |
| + _createSettingCheckBox(parent, id, config) { |
| + const setting = config.setting ? Common.settings.createSetting(config.setting, config.value) : null; |
| + const div = parent.createChild('div', 'recording-setting'); |
| + const checkbox = div.createChild('input'); |
| + checkbox.setAttribute('type', 'checkbox'); |
| + checkbox.setAttribute('id', id); |
| + if (setting ? setting.get() : config.value) |
| + checkbox.setAttribute('checked', true); |
| + if (setting) |
| + checkbox.addEventListener('change', event => setting.set(event.target.checked)); |
| + const label = div.createChild('label'); |
| + label.setAttribute('for', id); |
| + label.textContent = config.title; |
| + if (config.description) |
| + div.createChild('div', 'recording-setting-description').textContent = config.description; |
| + } |
| + |
| + action() { |
| + UI.actionRegistry.action('timeline.toggle-recording').execute(); |
| + } |
| +}; |
| + |
| +/** @typedef {!{value: boolean, title: string, description: string, setting: ?string}} */ |
| +Timeline.Perspective.Config; |
| + |
| +Timeline.LoadPerspective = class extends Timeline.Perspective { |
| + constructor() { |
| + super( |
| + Timeline.TimelinePanel.Perspectives.Load, Common.UIString('Page Load'), |
| + Common.UIString( |
| + 'Page Load mode allows you to analyze how fast the page is loaded and becomes responsive.\n' + |
| + 'In this mode the page is automatically reloaded right after the recording has started. ' + |
| + 'During recording it collects information about network requests, screen state updates, ' + |
| + 'and CPU threads acivity along with JavaScript stacks. ' + |
| + 'Recording is stopped automatically shortly after the page processes load event.'), |
| + ['screenshots']); |
| + this.settings.network.value = true; |
| + this.settings.reload.value = true; |
| + this.settings.screenshots.value = true; |
| + } |
| + |
| + /** |
| + * @override |
| + */ |
| + action() { |
| + SDK.targetManager.reloadPage(); |
| + } |
| +}; |
| + |
| +Timeline.ResponsivenessPerspective = class extends Timeline.Perspective { |
| + constructor() { |
| + super( |
| + Timeline.TimelinePanel.Perspectives.Responsiveness, Common.UIString('Responsiveness'), |
| + Common.UIString('Record page responsiveness.'), ['screenshots']); |
| + this.settings.network.value = true; |
| + } |
| +}; |
| + |
| +Timeline.JavaScriptPerspective = class extends Timeline.Perspective { |
| + constructor() { |
| + super( |
| + Timeline.TimelinePanel.Perspectives.JavaScript, Common.UIString('JavaScript'), |
| + Common.UIString('Record JavaScript execution profile.')); |
| + } |
| +}; |
| + |
| +Timeline.CustomPerspective = class extends Timeline.Perspective { |
| + constructor() { |
| + super( |
| + Timeline.TimelinePanel.Perspectives.Custom, Common.UIString('Custom'), |
| + Common.UIString('Advanced mode that allows you to customize recording options.'), |
| + ['network', 'javascript', 'screenshots', 'memory', 'paints']); |
| + } |
| +}; |
| + |
| +Timeline.LandingPage = class extends UI.VBox { |
| + constructor() { |
| + super(true); |
| + this.registerRequiredCSS('ui_lazy/dialog.css'); |
| + this.registerRequiredCSS('timeline/timelineLandingPage.css'); |
| + this.contentElement.classList.add('timeline-landing-page', 'fill'); |
| + const headerDiv = this.contentElement.createChild('div', 'timeline-perspective-header-bar'); |
| + this._perspectiveSetting = Common.settings.createSetting('timelinePerspective', 'load'); |
| + this._perspectiveSetting.addChangeListener(this._updatePerspective, this); |
| + |
| + this._perspectives = [ |
| + Timeline.LoadPerspective, Timeline.ResponsivenessPerspective, Timeline.JavaScriptPerspective, |
| + Timeline.CustomPerspective |
| + ].map(cls => new cls()); |
|
caseq
2016/12/07 20:17:29
let's just call constructors expecitly.
alph
2016/12/08 07:22:45
Done.
|
| + this._inputByPerspective = new Map(); |
| + for (const perspective of this._perspectives) { |
| + const div = headerDiv.createChild('div', 'timeline-perspective-header'); |
|
caseq
2016/12/07 20:17:29
Does this fail gracefully when the window is too n
alph
2016/12/08 07:22:45
Done.
|
| + const input = div.createChild('input'); |
| + input.setAttribute('type', 'radio'); |
| + input.setAttribute('name', 'perspective-select'); |
| + input.setAttribute('id', perspective.id); |
| + input.setAttribute('value', perspective.id); |
| + input.addEventListener('change', event => this._perspectiveSetting.set(event.target.id)); |
| + const label = div.createChild('label'); |
| + label.setAttribute('for', perspective.id); |
| + label.textContent = perspective.title; |
| + if (perspective.id === this._perspectiveSetting.get()) |
| + input.checked = true; |
| + this._inputByPerspective.set(perspective.id, input); |
| + } |
| + |
| + this._bodyDiv = this.contentElement.createChild('div', 'timeline-perspective-body'); |
| + const footer = this.contentElement.createChild('div', 'timeline-perspective-footer'); |
| + const actionButton = footer.createChild('button'); |
| + actionButton.textContent = Common.UIString('Start'); |
| + actionButton.addEventListener('click', this._onAction.bind(this)); |
| + this._updatePerspective(); |
| + } |
| + |
| + dispose() { |
| + this._perspectiveSetting.removeChangeListener(this._updatePerspective, this); |
|
caseq
2016/12/07 20:17:29
why do you need it?
alph
2016/12/08 07:22:45
Done.
|
| + } |
| + |
| + /** |
| + * @return {!Timeline.Perspective} |
| + */ |
| + _currentPerspective() { |
| + const id = this._perspectiveSetting.get(); |
| + return this._perspectives.find(p => p.id === id) || this._perspectives[0]; |
| + } |
| + |
| + _updatePerspective() { |
| + const perspective = this._currentPerspective(); |
| + const input = this._inputByPerspective.get(perspective.id); |
| + if (input && !input.checked) |
| + input.checked = true; |
| + this._bodyDiv.removeChildren(); |
| + this._bodyDiv.createChild('div', 'timeline-perspective-description').textContent = perspective.description; |
| + perspective.appendElements(this._bodyDiv); |
| + } |
| + |
| + _onAction() { |
| + this._currentPerspective().action(); |
| + } |
| +}; |