3 Copyright (c) 2013 The Chromium Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style license that can be
5 found in the LICENSE file.
7 <link rel="import" href="/tracing/filter.html">
8 <link rel="import" href="/tvcm/utils.html">
9 <link rel="import" href="/tvcm/ui/overlay.html">
10 <link rel="import" href="/tvcm/ui/dom_helpers.html">
11 <link rel="import" href="/tvcm/ui/info_bar.html">
13 <template id="record-selection-dialog-template">
15 .categories-column-view {
16 display: -webkit-flex;
17 -webkit-flex-direction: column;
18 font-family: sans-serif;
24 transition: max-height 1s ease, max-width 1s ease, opacity 1s ease;
28 .categories-column-view-hidden {
35 .categories-selection {
36 display: -webkit-flex;
37 -webkit-flex-direction: row;
44 .category-description {
52 transition: max-height 1s ease, opacity 1s ease;
56 .category-description-hidden {
61 .default-enabled-categories,
62 .default-disabled-categories {
63 -webkit-flex: 1 1 auto;
64 display: -webkit-flex;
65 -webkit-flex-direction: column;
70 .default-enabled-categories > div,
71 .default-disabled-categories > div {
76 -webkit-flex: 1 0 auto;
77 display: -webkit-flex;
78 -webkit-flex-direction: reverse;
80 border-bottom: 2px solid #ddd;
81 border-top: 2px solid #ddd;
84 .default-disabled-categories {
85 border-left: 2px solid #ddd;
88 .warning-default-disabled-categories {
89 display: inline-block;
96 border: 1px solid #BD2E2E;
104 -webkit-flex: 1 1 auto;
109 border-bottom: 1px solid #ddd;
111 -webkit-flex: 0 0 auto;
114 .group-selectors button {
119 <div class="record-selection-dialog">
120 <x-info-bar-group></x-info-bar-group>
121 <div class="category-presets">
124 <div class="category-description"></div>
125 <div class="categories-column-view">
126 <div class="tracing-modes"></div>
127 <div class="categories-selection">
128 <div class="default-enabled-categories">
129 <div>Record Categories</div>
130 <div class="group-selectors">
132 <button class="all-btn">All</button>
133 <button class="none-btn">None</button>
135 <div class="categories"></div>
137 <div class="default-disabled-categories">
138 <div>Disabled by Default Categories
139 <a class="warning-default-disabled-categories">!</a>
141 <div class="group-selectors">
143 <button class="all-btn">All</button>
144 <button class="none-btn">None</button>
146 <div class="categories"></div>
157 * @fileoverview RecordSelectionDialog presents the available categories
158 * to be enabled/disabled during tracing.
160 tvcm.exportTo('about_tracing', function() {
161 var THIS_DOC = document.currentScript.ownerDocument;
162 var RecordSelectionDialog = tvcm.ui.define('div');
164 var DEFAULT_PRESETS = [
165 {title: 'Web developer',
166 categoryFilter: ['blink', 'cc', 'net', 'v8']},
167 {title: 'Input latency',
168 categoryFilter: ['benchmark', 'input']},
170 categoryFilter: ['blink', 'cc', 'gpu']},
171 {title: 'Javascript and rendering',
172 categoryFilter: ['blink', 'cc', 'gpu', 'v8']},
173 {title: 'Frame Viewer',
174 categoryFilter: ['blink', 'cc', 'gpu', 'v8',
175 'disabled-by-default-cc.debug']},
176 {title: 'Manually select settings',
179 var DEFAULT_CONTINUOUS_TRACING = true;
180 var DEFAULT_SYSTEM_TRACING = false;
181 var DEFAULT_SAMPLING_TRACING = false;
183 RecordSelectionDialog.prototype = {
184 __proto__: tvcm.ui.Overlay.prototype,
186 decorate: function() {
187 tvcm.ui.Overlay.prototype.decorate.call(this);
188 this.title = 'Record a new trace...';
190 this.classList.add('record-dialog-overlay');
192 var node = tvcm.instantiateTemplate('#record-selection-dialog-template',
194 this.appendChild(node);
196 this.recordButtonEl_ = document.createElement('button');
197 this.recordButtonEl_.textContent = 'Record';
198 this.recordButtonEl_.addEventListener(
200 this.onRecordButtonClicked_.bind(this));
201 this.recordButtonEl_.style.fontSize = '110%';
202 this.buttons.appendChild(this.recordButtonEl_);
205 this.categoriesView_ = this.querySelector('.categories-column-view');
206 this.presetsEl_ = this.querySelector('.category-presets');
207 this.presetsEl_.appendChild(tvcm.ui.createSelector(
208 this, 'currentlyChosenPreset',
209 'about_tracing.record_selection_dialog_preset',
210 DEFAULT_PRESETS[0].categoryFilter,
211 DEFAULT_PRESETS.map(function(p) {
212 return { label: p.title, value: p.categoryFilter };
216 this.continuousTracingBn_ = tvcm.ui.createCheckBox(
217 undefined, undefined,
218 'recordSelectionDialog.useContinuousTracing', true,
219 'Continuous tracing');
220 this.systemTracingBn_ = tvcm.ui.createCheckBox(
221 undefined, undefined,
222 'recordSelectionDialog.useSystemTracing', true,
224 this.samplingTracingBn_ = tvcm.ui.createCheckBox(
225 undefined, undefined,
226 'recordSelectionDialog.useSampling', false,
228 this.tracingModesContainerEl_ = this.querySelector('.tracing-modes');
229 this.tracingModesContainerEl_.appendChild(this.continuousTracingBn_);
230 this.tracingModesContainerEl_.appendChild(this.systemTracingBn_);
231 this.tracingModesContainerEl_.appendChild(this.samplingTracingBn_);
234 this.enabledCategoriesContainerEl_ =
235 this.querySelector('.default-enabled-categories .categories');
237 this.disabledCategoriesContainerEl_ =
238 this.querySelector('.default-disabled-categories .categories');
240 this.createGroupSelectButtons_(
241 this.querySelector('.default-enabled-categories'));
242 this.createGroupSelectButtons_(
243 this.querySelector('.default-disabled-categories'));
244 this.createDefaultDisabledWarningDialog_(
245 this.querySelector('.warning-default-disabled-categories'));
247 // TODO(chrishenry): When used with tvcm.ui.Overlay (such as in
248 // chrome://tracing, this does not yet look quite right due to
249 // the 10px overlay content padding (but it's good enough).
250 this.infoBarGroup_ = this.querySelector('x-info-bar-group');
251 tvcm.ui.decorate(this.infoBarGroup_, tvcm.ui.InfoBarGroup);
253 this.addEventListener('visibleChange', this.onVisibleChange_.bind(this));
256 set supportsSystemTracing(s) {
258 this.systemTracingBn_.style.display = undefined;
260 this.systemTracingBn_.style.display = 'none';
261 this.useSystemTracing = false;
265 get useContinuousTracing() {
266 if (this.usingPreset_())
267 return DEFAULT_CONTINUOUS_TRACING;
268 return this.continuousTracingBn_.checked;
270 set useContinuousTracing(value) {
271 this.continuousTracingBn_.checked = !!value;
274 get useSystemTracing() {
275 if (this.usingPreset_())
276 return DEFAULT_SYSTEM_TRACING;
277 return this.systemTracingBn_.checked;
279 set useSystemTracing(value) {
280 this.systemTracingBn_.checked = !!value;
283 if (this.usingPreset_())
284 return DEFAULT_SAMPLING_TRACING;
285 return this.samplingTracingBn_.checked;
287 set useSampling(value) {
288 this.samplingTracingBn_.checked = !!value;
292 this.categories_ = c;
294 for (var i = 0; i < this.categories_.length; i++) {
295 var split = this.categories_[i].split(',');
296 this.categories_[i] = split.shift();
297 if (split.length > 0)
298 this.categories_ = this.categories_.concat(split);
302 set settings_key(k) {
303 this.settings_key_ = k;
307 throw new Error('Dont use this!');
310 usingPreset_: function() {
311 return this.currentlyChosenPreset_.length > 0;
314 get currentlyChosenPreset() {
315 return this.currentlyChosenPreset_;
318 set currentlyChosenPreset(preset) {
319 if (!(preset instanceof Array))
320 throw new Error('RecordSelectionDialog.currentlyChosenPreset:' +
321 ' preset must be an array.');
322 this.currentlyChosenPreset_ = preset;
324 var classList = this.categoriesView_.classList;
325 if (!this.usingPreset_())
326 classList.remove('categories-column-view-hidden');
327 else if (!classList.contains('categories-column-view-hidden'))
328 classList.add('categories-column-view-hidden');
329 this.updatePresetDescription_();
332 updatePresetDescription_: function() {
333 var description = this.querySelector('.category-description');
334 if (this.usingPreset_()) {
335 description.innerText = this.currentlyChosenPreset_;
336 description.classList.remove('category-description-hidden');
338 description.innerText = '';
339 if (!description.classList.contains('category-description-hidden'))
340 description.classList.add('category-description-hidden');
344 categoryFilter: function() {
345 if (this.usingPreset_()) {
347 var allCategories = this.allCategories_();
348 for (var category in allCategories) {
349 var disabled = category.indexOf('disabled-by-default-') == 0;
350 if (this.currentlyChosenPreset_.indexOf(category) >= 0) {
352 categories.push(category);
355 categories.push('-' + category);
358 return categories.join(',');
361 var categories = this.unselectedCategories_();
362 var categories_length = categories.length;
363 var negated_categories = [];
364 for (var i = 0; i < categories_length; ++i) {
365 // Skip any category with a , as it will cause issues when we negate.
366 // Both sides should have been added as separate categories, these can
367 // only come from settings.
368 if (categories[i].match(/,/))
370 negated_categories.push('-' + categories[i]);
372 categories = negated_categories.join(',');
374 var disabledCategories = this.enabledDisabledByDefaultCategories_();
375 disabledCategories = disabledCategories.join(',');
378 if (categories !== '')
379 results.push(categories);
380 if (disabledCategories !== '')
381 results.push(disabledCategories);
382 return results.join(',');
385 clickRecordButton: function() {
386 this.recordButtonEl_.click();
389 onRecordButtonClicked_: function() {
390 this.visible = false;
391 tvcm.dispatchSimpleEvent(this, 'recordclick');
395 collectInputs_: function(inputs, isChecked) {
396 var inputs_length = inputs.length;
398 for (var i = 0; i < inputs_length; ++i) {
399 var input = inputs[i];
400 if (input.checked === isChecked)
401 categories.push(input.value);
406 unselectedCategories_: function() {
408 this.enabledCategoriesContainerEl_.querySelectorAll('input');
409 return this.collectInputs_(inputs, false);
412 enabledDisabledByDefaultCategories_: function() {
414 this.disabledCategoriesContainerEl_.querySelectorAll('input');
415 return this.collectInputs_(inputs, true);
418 onVisibleChange_: function() {
423 buildInputs_: function(inputs, checkedDefault, parent) {
424 var inputs_length = inputs.length;
425 for (var i = 0; i < inputs_length; i++) {
426 var category = inputs[i];
428 var inputEl = document.createElement('input');
429 inputEl.type = 'checkbox';
430 inputEl.id = category;
431 inputEl.value = category;
433 inputEl.checked = tvcm.Settings.get(
434 category, checkedDefault, this.settings_key_);
435 inputEl.onclick = this.updateSetting_.bind(this);
437 var labelEl = document.createElement('label');
438 labelEl.textContent = category.replace('disabled-by-default-', '');
439 labelEl.setAttribute('for', category);
441 var divEl = document.createElement('div');
442 divEl.appendChild(inputEl);
443 divEl.appendChild(labelEl);
445 parent.appendChild(divEl);
449 allCategories_: function() {
450 // Dedup the categories. We may have things in settings that are also
451 // returned when we query the category list.
452 var categorySet = {};
454 this.categories_.concat(tvcm.Settings.keys(this.settings_key_));
455 var allCategoriesLength = allCategories.length;
456 for (var i = 0; i < allCategoriesLength; ++i)
457 categorySet[allCategories[i]] = true;
461 updateForm_: function() {
462 this.enabledCategoriesContainerEl_.innerHTML = ''; // Clear old categories
463 this.disabledCategoriesContainerEl_.innerHTML = '';
465 this.recordButtonEl_.focus();
467 var allCategories = this.allCategories_();
469 var disabledCategories = [];
470 for (var category in allCategories) {
471 if (category.indexOf('disabled-by-default-') == 0)
472 disabledCategories.push(category);
474 categories.push(category);
476 disabledCategories = disabledCategories.sort();
477 categories = categories.sort();
479 if (this.categories_.length == 0) {
480 this.infoBarGroup_.addMessage(
481 'No categories found; recording will use default categories.');
484 this.buildInputs_(categories, true, this.enabledCategoriesContainerEl_);
486 if (disabledCategories.length > 0) {
487 this.disabledCategoriesContainerEl_.hidden = false;
488 this.buildInputs_(disabledCategories, false,
489 this.disabledCategoriesContainerEl_);
493 updateSetting_: function(e) {
494 var checkbox = e.target;
495 tvcm.Settings.set(checkbox.value, checkbox.checked, this.settings_key_);
498 createGroupSelectButtons_: function(parent) {
499 var flipInputs = function(dir) {
500 var inputs = parent.querySelectorAll('input');
501 for (var i = 0; i < inputs.length; i++) {
502 if (inputs[i].checked === dir)
504 // click() is used so the settings will be correclty stored. Setting
505 // checked does not trigger the onclick (or onchange) callback.
510 var allBtn = parent.querySelector('.all-btn');
511 allBtn.onclick = function(evt) {
513 evt.preventDefault();
516 var noneBtn = parent.querySelector('.none-btn');
517 noneBtn.onclick = function(evt) {
519 evt.preventDefault();
523 setWarningDialogOverlayText_: function(messages) {
524 var contentDiv = document.createElement('div');
526 for (var i = 0; i < messages.length; ++i) {
527 var messageDiv = document.createElement('div');
528 messageDiv.textContent = messages[i];
529 contentDiv.appendChild(messageDiv);
531 this.warningOverlay_.textContent = '';
532 this.warningOverlay_.appendChild(contentDiv);
535 createDefaultDisabledWarningDialog_: function(warningLink) {
536 function onClickHandler(evt) {
537 this.warningOverlay_ = tvcm.ui.Overlay();
538 this.warningOverlay_.title = 'Enabling Categories Warning...';
539 this.warningOverlay_.userCanClose = true;
540 this.warningOverlay_.visible = true;
542 this.setWarningDialogOverlayText_([
543 'Enabling the default disabled categories may have',
544 'performance and memory impact while tracing.'
547 evt.preventDefault();
549 warningLink.onclick = onClickHandler.bind(this);
554 RecordSelectionDialog: RecordSelectionDialog