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.
6 * Dictionary of constants (Initialized soon after loading by data from browser,
7 * updated on load log). The *Types dictionaries map strings to numeric IDs,
8 * while the *TypeNames are the other way around.
11 var EventTypeNames
= null;
12 var EventPhase
= null;
13 var EventSourceType
= null;
14 var EventSourceTypeNames
= null;
15 var ClientInfo
= null;
18 var QuicRstStreamError
= null;
20 var CertStatusFlag
= null;
22 var AddressFamily
= null;
23 var SdchProblemCode
= null;
24 var DataReductionProxyBypassEventType
= null;
27 * Dictionary of all constants, used for saving log files.
32 * Object to communicate between the renderer and the browser.
33 * @type {!BrowserBridge}
38 * This class is the root view object of the page. It owns all the other
39 * views, and manages switching between them. It is also responsible for
40 * initializing the views and the BrowserBridge.
42 var MainView
= (function() {
45 // We inherit from WindowView
46 var superClass
= WindowView
;
49 * Main entry point. Called once the page has loaded.
53 assertFirstConstructorCall(MainView
);
56 document
.body
.classList
.add('touch');
58 // This must be initialized before the tabs, so they can register as
60 g_browser
= BrowserBridge
.getInstance();
62 // This must be the first constants observer, so other constants observers
63 // can safely use the globals, rather than depending on walking through
64 // the constants themselves.
65 g_browser
.addConstantsObserver(new ConstantsObserver());
67 // Create the tab switcher.
70 // Cut out a small vertical strip at the top of the window, to display
71 // a high level status (i.e. if we are capturing events, or displaying a
72 // log file). Below it we will position the main tabs and their content
74 this.topBarView_
= TopBarView
.getInstance(this);
75 var verticalSplitView
= new VerticalSplitView(
76 this.topBarView_
, this.tabSwitcher_
);
78 superClass
.call(this, verticalSplitView
);
80 // Trigger initial layout.
83 window
.onhashchange
= this.onUrlHashChange_
.bind(this);
85 // Select the initial view based on the current URL.
86 window
.onhashchange();
88 // Tell the browser that we are ready to start receiving log events.
89 this.topBarView_
.switchToSubView('capture');
90 g_browser
.sendReady();
93 cr
.addSingletonGetter(MainView
);
95 // Tracks if we're viewing a loaded log file, so views can behave
96 // appropriately. Global so safe to call during construction.
97 var isViewingLoadedLog
= false;
99 MainView
.isViewingLoadedLog = function() {
100 return isViewingLoadedLog
;
103 MainView
.prototype = {
104 // Inherit the superclass's methods.
105 __proto__
: superClass
.prototype,
107 // This is exposed both so the log import/export code can enumerate all the
108 // tabs, and for testing.
109 tabSwitcher: function() {
110 return this.tabSwitcher_
;
114 * Prevents receiving/sending events to/from the browser, so loaded data
115 * will not be mixed with current Chrome state. Also hides any interactive
116 * HTML elements that send messages to the browser. Cannot be undone
117 * without reloading the page. Must be called before passing loaded data
118 * to the individual views.
120 * @param {string} opt_fileName The name of the log file that has been
121 * loaded, if we're loading a log file.
123 onLoadLog: function(opt_fileName
) {
124 isViewingLoadedLog
= true;
126 this.stopCapturing();
127 if (opt_fileName
!= undefined) {
128 // If there's a file name, a log file was loaded, so swap out the status
129 // bar to indicate we're no longer capturing events. Also disable
130 // hiding cookies, so if the log dump has them, they'll be displayed.
131 this.topBarView_
.switchToSubView('loaded').setFileName(opt_fileName
);
132 $(ExportView
.PRIVACY_STRIPPING_CHECKBOX_ID
).checked
= false;
133 SourceTracker
.getInstance().setPrivacyStripping(false);
135 // Otherwise, the "Stop Capturing" button was presumably pressed.
136 // Don't disable hiding cookies, so created log dumps won't have them,
137 // unless the user toggles the option.
138 this.topBarView_
.switchToSubView('halted');
142 switchToViewOnlyMode: function() {
143 // Since this won't be dumped to a file, we don't want to remove
144 // cookies and credentials.
145 log_util
.createLogDumpAsync('', log_util
.loadLogFile
, false);
148 stopCapturing: function() {
150 document
.styleSheets
[0].insertRule(
151 '.hide-when-not-capturing { display: none; }', 0);
154 initTabs_: function() {
155 this.tabIdToHash_
= {};
156 this.hashToTabId_
= {};
158 this.tabSwitcher_
= new TabSwitcherView(
159 $(TopBarView
.TAB_DROPDOWN_MENU_ID
),
160 this.onTabSwitched_
.bind(this));
162 // Helper function to add a tab given the class for a view singleton.
163 var addTab = function(viewClass
) {
164 var tabId
= viewClass
.TAB_ID
;
165 var tabHash
= viewClass
.TAB_HASH
;
166 var tabName
= viewClass
.TAB_NAME
;
167 var view
= viewClass
.getInstance();
169 if (!tabId
|| !view
|| !tabHash
|| !tabName
) {
170 throw Error('Invalid view class for tab');
173 if (tabHash
.charAt(0) != '#') {
174 throw Error('Tab hashes must start with a #');
177 this.tabSwitcher_
.addTab(tabId
, view
, tabName
);
178 this.tabIdToHash_
[tabId
] = tabHash
;
179 this.hashToTabId_
[tabHash
] = tabId
;
182 // Populate the main tabs. Even tabs that don't contain information for
183 // the running OS should be created, so they can load log dumps from other
190 addTab(WaterfallView
);
191 addTab(TimelineView
);
197 addTab(HttpCacheView
);
200 addTab(BandwidthView
);
201 addTab(PrerenderView
);
204 this.tabSwitcher_
.showMenuItem(CrosView
.TAB_ID
, cr
.isChromeOS
);
208 * This function is called by the tab switcher when the current tab has been
209 * changed. It will update the current URL to reflect the new active tab,
210 * so the back can be used to return to previous view.
212 onTabSwitched_: function(oldTabId
, newTabId
) {
213 // Update data needed by newly active tab, as it may be
214 // significantly out of date.
216 g_browser
.checkForUpdatedInfo();
218 // Change the URL to match the new tab.
220 var newTabHash
= this.tabIdToHash_
[newTabId
];
221 var parsed
= parseUrlHash_(window
.location
.hash
);
222 if (parsed
.tabHash
!= newTabHash
) {
223 window
.location
.hash
= newTabHash
;
227 onUrlHashChange_: function() {
228 var parsed
= parseUrlHash_(window
.location
.hash
);
233 if (!parsed
.tabHash
) {
234 // Default to the export tab.
235 parsed
.tabHash
= ExportView
.TAB_HASH
;
238 var tabId
= this.hashToTabId_
[parsed
.tabHash
];
241 this.tabSwitcher_
.switchToTab(tabId
);
242 if (parsed
.parameters
) {
243 var view
= this.tabSwitcher_
.getTabView(tabId
);
244 view
.setParameters(parsed
.parameters
);
252 * Takes the current hash in form of "#tab¶m1=value1¶m2=value2&..."
253 * and parses it into a dictionary.
255 * Parameters and values are decoded with decodeURIComponent().
257 function parseUrlHash_(hash
) {
258 var parameters
= hash
.split('&');
260 var tabHash
= parameters
[0];
261 if (tabHash
== '' || tabHash
== '#') {
265 // Split each string except the first around the '='.
266 var paramDict
= null;
267 for (var i
= 1; i
< parameters
.length
; i
++) {
268 var paramStrings
= parameters
[i
].split('=');
269 if (paramStrings
.length
!= 2)
271 if (paramDict
== null)
273 var key
= decodeURIComponent(paramStrings
[0]);
274 var value
= decodeURIComponent(paramStrings
[1]);
275 paramDict
[key
] = value
;
278 return {tabHash
: tabHash
, parameters
: paramDict
};
284 function ConstantsObserver() {}
287 * Loads all constants from |constants|. On failure, global dictionaries are
289 * @param {Object} receivedConstants The map of received constants.
291 ConstantsObserver
.prototype.onReceivedConstants = function(receivedConstants
) {
292 if (!areValidConstants(receivedConstants
))
295 Constants
= receivedConstants
;
297 EventType
= Constants
.logEventTypes
;
298 EventTypeNames
= makeInverseMap(EventType
);
299 EventPhase
= Constants
.logEventPhase
;
300 EventSourceType
= Constants
.logSourceType
;
301 EventSourceTypeNames
= makeInverseMap(EventSourceType
);
302 ClientInfo
= Constants
.clientInfo
;
303 LoadFlag
= Constants
.loadFlag
;
304 NetError
= Constants
.netError
;
305 QuicError
= Constants
.quicError
;
306 QuicRstStreamError
= Constants
.quicRstStreamError
;
307 AddressFamily
= Constants
.addressFamily
;
308 LoadState
= Constants
.loadState
;
309 SdchProblemCode
= Constants
.sdchProblemCode
;
310 DataReductionProxyBypassEventType
=
311 Constants
.dataReductionProxyBypassEventType
;
312 DataReductionProxyBypassActionType
=
313 Constants
.dataReductionProxyBypassActionType
;
314 // certStatusFlag may not be present when loading old log Files
315 if (typeof(Constants
.certStatusFlag
) == 'object')
316 CertStatusFlag
= Constants
.certStatusFlag
;
320 timeutil
.setTimeTickOffset(Constants
.timeTickOffset
);
324 * Returns true if it's given a valid-looking constants object.
325 * @param {Object} receivedConstants The received map of constants.
326 * @return {boolean} True if the |receivedConstants| object appears valid.
328 function areValidConstants(receivedConstants
) {
329 return typeof(receivedConstants
) == 'object' &&
330 typeof(receivedConstants
.logEventTypes
) == 'object' &&
331 typeof(receivedConstants
.clientInfo
) == 'object' &&
332 typeof(receivedConstants
.logEventPhase
) == 'object' &&
333 typeof(receivedConstants
.logSourceType
) == 'object' &&
334 typeof(receivedConstants
.loadFlag
) == 'object' &&
335 typeof(receivedConstants
.netError
) == 'object' &&
336 typeof(receivedConstants
.addressFamily
) == 'object' &&
337 typeof(receivedConstants
.timeTickOffset
) == 'string' &&
338 typeof(receivedConstants
.logFormatVersion
) == 'number';
342 * Returns the name for netError.
344 * Example: netErrorToString(-105) should return
345 * "ERR_NAME_NOT_RESOLVED".
346 * @param {number} netError The net error code.
347 * @return {string} The name of the given error.
349 function netErrorToString(netError
) {
350 return getKeyWithValue(NetError
, netError
);
354 * Returns the name for quicError.
356 * Example: quicErrorToString(25) should return
358 * @param {number} quicError The QUIC error code.
359 * @return {string} The name of the given error.
361 function quicErrorToString(quicError
) {
362 return getKeyWithValue(QuicError
, quicError
);
366 * Returns the name for quicRstStreamError.
368 * Example: quicRstStreamErrorToString(3) should return
369 * "BAD_APPLICATION_PAYLOAD".
370 * @param {number} quicRstStreamError The QUIC RST_STREAM error code.
371 * @return {string} The name of the given error.
373 function quicRstStreamErrorToString(quicRstStreamError
) {
374 return getKeyWithValue(QuicRstStreamError
, quicRstStreamError
);
378 * Returns a string representation of |family|.
379 * @param {number} family An AddressFamily
380 * @return {string} A representation of the given family.
382 function addressFamilyToString(family
) {
383 var str
= getKeyWithValue(AddressFamily
, family
);
384 // All the address family start with ADDRESS_FAMILY_*.
385 // Strip that prefix since it is redundant and only clutters the output.
386 return str
.replace(/^ADDRESS_FAMILY_/, '');
390 * Returns the name for sdchProblemCode.
392 * Example: sdchProblemCodeToString(5) should return
393 * "DECODE_BODY_ERROR".
394 * @param {number} sdchProblemCode The SDCH problem code.
395 * @return {string} The name of the given problem code.
397 function sdchProblemCodeToString(sdchProblemCode
) {
398 return getKeyWithValue(SdchProblemCode
, sdchProblemCode
);