1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/**
6 * This variable structure is here to document the structure that the template
7 * expects to correctly populate the page.
8 */
9
10/**
11 * Takes the |experimentsData| input argument which represents data about all
12 * the current experiments and populates the html jstemplate with that data.
13 * with that data. It expects an object structure like the above.
14 * @param {Object} experimentsData Information about all experiments.
15 *     See returnFlagsExperiments() for the structure of this object.
16 */
17function renderTemplate(experimentsData) {
18  // This is the javascript code that processes the template:
19  jstProcess(new JsEvalContext(experimentsData),
20             $('flagsExperimentTemplate'));
21
22  // Add handlers to dynamically created HTML elements.
23  var elements = document.getElementsByClassName('experiment-select');
24  for (var i = 0; i < elements.length; ++i) {
25    elements[i].onchange = function() {
26      handleSelectChoiceExperiment(this, this.selectedIndex);
27      return false;
28    };
29  }
30
31  elements = document.getElementsByClassName('experiment-disable-link');
32  for (var i = 0; i < elements.length; ++i) {
33    elements[i].onclick = function() {
34      handleEnableExperiment(this, false);
35      return false;
36    };
37  }
38
39  elements = document.getElementsByClassName('experiment-enable-link');
40  for (var i = 0; i < elements.length; ++i) {
41    elements[i].onclick = function() {
42      handleEnableExperiment(this, true);
43      return false;
44    };
45  }
46
47  elements = document.getElementsByClassName('experiment-restart-button');
48  for (var i = 0; i < elements.length; ++i) {
49    elements[i].onclick = restartBrowser;
50  }
51
52  $('experiment-reset-all').onclick = resetAllFlags;
53
54  highlightReferencedFlag();
55}
56
57/**
58 * Highlight an element associated with the page's location's hash. We need to
59 * fake fragment navigation with '.scrollIntoView()', since the fragment IDs
60 * don't actually exist until after the template code runs; normal navigation
61 * therefore doesn't work.
62 */
63function highlightReferencedFlag() {
64  if (window.location.hash) {
65    var el = document.querySelector(window.location.hash);
66    if (el && !el.classList.contains('referenced')) {
67      // Unhighlight whatever's highlighted.
68      if (document.querySelector('.referenced'))
69        document.querySelector('.referenced').classList.remove('referenced');
70      // Highlight the referenced element.
71      el.classList.add('referenced');
72      el.scrollIntoView();
73    }
74  }
75}
76
77/**
78 * Asks the C++ FlagsDOMHandler to get details about the available experiments
79 * and return detailed data about the configuration. The FlagsDOMHandler
80 * should reply to returnFlagsExperiments() (below).
81 */
82function requestFlagsExperimentsData() {
83  chrome.send('requestFlagsExperiments');
84}
85
86/**
87 * Asks the C++ FlagsDOMHandler to restart the browser (restoring tabs).
88 */
89function restartBrowser() {
90  chrome.send('restartBrowser');
91}
92
93/**
94 * Reset all flags to their default values and refresh the UI.
95 */
96function resetAllFlags() {
97  // Asks the C++ FlagsDOMHandler to reset all flags to default values.
98  chrome.send('resetAllFlags');
99  requestFlagsExperimentsData();
100}
101
102/**
103 * Called by the WebUI to re-populate the page with data representing the
104 * current state of all experiments.
105 * @param {Object} experimentsData Information about all experiments.
106 *     in the following format:
107 *   {
108 *     supportedExperiments: [
109 *       {
110 *         internal_name: 'Experiment ID string',
111 *         name: 'Experiment Name',
112 *         description: 'description',
113 *         // enabled is only set if the experiment is single valued.
114 *         enabled: true,
115 *         // choices is only set if the experiment has multiple values.
116 *         choices: [
117 *           {
118 *             internal_name: 'Experiment ID string',
119 *             description: 'description',
120 *             selected: true
121 *           }
122 *         ],
123 *         supported_platforms: [
124 *           'Mac',
125 *           'Linux'
126 *         ],
127 *       }
128 *     ],
129 *     unsupportedExperiments: [
130 *       // Mirrors the format of |supportedExperiments| above.
131 *     ],
132 *     needsRestart: false,
133 *     showBetaChannelPromotion: false,
134 *     showDevChannelPromotion: false
135 *   }
136 */
137function returnFlagsExperiments(experimentsData) {
138  var bodyContainer = $('body-container');
139  renderTemplate(experimentsData);
140
141  if (experimentsData.showBetaChannelPromotion)
142    $('channel-promo-beta').hidden = false;
143  else if (experimentsData.showDevChannelPromotion)
144    $('channel-promo-dev').hidden = false;
145
146  bodyContainer.style.visibility = 'visible';
147}
148
149/**
150 * Handles a 'enable' or 'disable' button getting clicked.
151 * @param {HTMLElement} node The node for the experiment being changed.
152 * @param {boolean} enable Whether to enable or disable the experiment.
153 */
154function handleEnableExperiment(node, enable) {
155  // Tell the C++ FlagsDOMHandler to enable/disable the experiment.
156  chrome.send('enableFlagsExperiment', [String(node.internal_name),
157                                        String(enable)]);
158  requestFlagsExperimentsData();
159}
160
161/**
162 * Invoked when the selection of a multi-value choice is changed to the
163 * specified index.
164 * @param {HTMLElement} node The node for the experiment being changed.
165 * @param {number} index The index of the option that was selected.
166 */
167function handleSelectChoiceExperiment(node, index) {
168  // Tell the C++ FlagsDOMHandler to enable the selected choice.
169  chrome.send('enableFlagsExperiment',
170              [String(node.internal_name) + '@' + index, 'true']);
171  requestFlagsExperimentsData();
172}
173
174// Get data and have it displayed upon loading.
175document.addEventListener('DOMContentLoaded', requestFlagsExperimentsData);
176
177// Update the highlighted flag when the hash changes.
178window.addEventListener('hashchange', highlightReferencedFlag);
179