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 LogLevelType
= null;
16 var ClientInfo
= null;
19 var QuicRstStreamError
= null;
21 var CertStatusFlag
= null;
23 var AddressFamily
= null;
24 var SdchProblemCode
= null;
25 var DataReductionProxyBypassEventType
= null;
28 * Dictionary of all constants, used for saving log files.
33 * Object to communicate between the renderer and the browser.
34 * @type {!BrowserBridge}
39 * This class is the root view object of the page. It owns all the other
40 * views, and manages switching between them. It is also responsible for
41 * initializing the views and the BrowserBridge.
43 var MainView
= (function() {
46 // We inherit from WindowView
47 var superClass
= WindowView
;
50 * Main entry point. Called once the page has loaded.
54 assertFirstConstructorCall(MainView
);
57 document
.body
.classList
.add('touch');
59 // This must be initialized before the tabs, so they can register as
61 g_browser
= BrowserBridge
.getInstance();
63 // This must be the first constants observer, so other constants observers
64 // can safely use the globals, rather than depending on walking through
65 // the constants themselves.
66 g_browser
.addConstantsObserver(new ConstantsObserver());
68 // Create the tab switcher.
71 // Cut out a small vertical strip at the top of the window, to display
72 // a high level status (i.e. if we are capturing events, or displaying a
73 // log file). Below it we will position the main tabs and their content
75 this.topBarView_
= TopBarView
.getInstance(this);
76 var verticalSplitView
= new VerticalSplitView(
77 this.topBarView_
, this.tabSwitcher_
);
79 superClass
.call(this, verticalSplitView
);
81 // Trigger initial layout.
84 window
.onhashchange
= this.onUrlHashChange_
.bind(this);
86 // Select the initial view based on the current URL.
87 window
.onhashchange();
89 // Tell the browser that we are ready to start receiving log events.
90 this.topBarView_
.switchToSubView('capture');
91 g_browser
.sendReady();
94 cr
.addSingletonGetter(MainView
);
96 // Tracks if we're viewing a loaded log file, so views can behave
97 // appropriately. Global so safe to call during construction.
98 var isViewingLoadedLog
= false;
100 MainView
.isViewingLoadedLog = function() {
101 return isViewingLoadedLog
;
104 MainView
.prototype = {
105 // Inherit the superclass's methods.
106 __proto__
: superClass
.prototype,
108 // This is exposed both so the log import/export code can enumerate all the
109 // tabs, and for testing.
110 tabSwitcher: function() {
111 return this.tabSwitcher_
;
115 * Prevents receiving/sending events to/from the browser, so loaded data
116 * will not be mixed with current Chrome state. Also hides any interactive
117 * HTML elements that send messages to the browser. Cannot be undone
118 * without reloading the page. Must be called before passing loaded data
119 * to the individual views.
121 * @param {string} opt_fileName The name of the log file that has been
122 * loaded, if we're loading a log file.
124 onLoadLog: function(opt_fileName
) {
125 isViewingLoadedLog
= true;
127 this.stopCapturing();
128 if (opt_fileName
!= undefined) {
129 // If there's a file name, a log file was loaded, so swap out the status
130 // bar to indicate we're no longer capturing events. Also disable
131 // hiding cookies, so if the log dump has them, they'll be displayed.
132 this.topBarView_
.switchToSubView('loaded').setFileName(opt_fileName
);
133 $(ExportView
.PRIVACY_STRIPPING_CHECKBOX_ID
).checked
= false;
134 SourceTracker
.getInstance().setPrivacyStripping(false);
136 // Otherwise, the "Stop Capturing" button was presumably pressed.
137 // Don't disable hiding cookies, so created log dumps won't have them,
138 // unless the user toggles the option.
139 this.topBarView_
.switchToSubView('halted');
143 switchToViewOnlyMode: function() {
144 // Since this won't be dumped to a file, we don't want to remove
145 // cookies and credentials.
146 log_util
.createLogDumpAsync('', log_util
.loadLogFile
, false);
149 stopCapturing: function() {
151 document
.styleSheets
[0].insertRule(
152 '.hide-when-not-capturing { display: none; }', 0);
155 initTabs_: function() {
156 this.tabIdToHash_
= {};
157 this.hashToTabId_
= {};
159 this.tabSwitcher_
= new TabSwitcherView(
160 $(TopBarView
.TAB_DROPDOWN_MENU_ID
),
161 this.onTabSwitched_
.bind(this));
163 // Helper function to add a tab given the class for a view singleton.
164 var addTab = function(viewClass
) {
165 var tabId
= viewClass
.TAB_ID
;
166 var tabHash
= viewClass
.TAB_HASH
;
167 var tabName
= viewClass
.TAB_NAME
;
168 var view
= viewClass
.getInstance();
170 if (!tabId
|| !view
|| !tabHash
|| !tabName
) {
171 throw Error('Invalid view class for tab');
174 if (tabHash
.charAt(0) != '#') {
175 throw Error('Tab hashes must start with a #');
178 this.tabSwitcher_
.addTab(tabId
, view
, tabName
);
179 this.tabIdToHash_
[tabId
] = tabHash
;
180 this.hashToTabId_
[tabHash
] = tabId
;
183 // Populate the main tabs. Even tabs that don't contain information for
184 // the running OS should be created, so they can load log dumps from other
191 addTab(WaterfallView
);
192 addTab(TimelineView
);
198 addTab(HttpCacheView
);
202 addTab(BandwidthView
);
203 addTab(PrerenderView
);
206 this.tabSwitcher_
.showMenuItem(CrosView
.TAB_ID
, cr
.isChromeOS
);
210 * This function is called by the tab switcher when the current tab has been
211 * changed. It will update the current URL to reflect the new active tab,
212 * so the back can be used to return to previous view.
214 onTabSwitched_: function(oldTabId
, newTabId
) {
215 // Update data needed by newly active tab, as it may be
216 // significantly out of date.
218 g_browser
.checkForUpdatedInfo();
220 // Change the URL to match the new tab.
222 var newTabHash
= this.tabIdToHash_
[newTabId
];
223 var parsed
= parseUrlHash_(window
.location
.hash
);
224 if (parsed
.tabHash
!= newTabHash
) {
225 window
.location
.hash
= newTabHash
;
229 onUrlHashChange_: function() {
230 var parsed
= parseUrlHash_(window
.location
.hash
);
235 if (!parsed
.tabHash
) {
236 // Default to the export tab.
237 parsed
.tabHash
= ExportView
.TAB_HASH
;
240 var tabId
= this.hashToTabId_
[parsed
.tabHash
];
243 this.tabSwitcher_
.switchToTab(tabId
);
244 if (parsed
.parameters
) {
245 var view
= this.tabSwitcher_
.getTabView(tabId
);
246 view
.setParameters(parsed
.parameters
);
254 * Takes the current hash in form of "#tab¶m1=value1¶m2=value2&..."
255 * and parses it into a dictionary.
257 * Parameters and values are decoded with decodeURIComponent().
259 function parseUrlHash_(hash
) {
260 var parameters
= hash
.split('&');
262 var tabHash
= parameters
[0];
263 if (tabHash
== '' || tabHash
== '#') {
267 // Split each string except the first around the '='.
268 var paramDict
= null;
269 for (var i
= 1; i
< parameters
.length
; i
++) {
270 var paramStrings
= parameters
[i
].split('=');
271 if (paramStrings
.length
!= 2)
273 if (paramDict
== null)
275 var key
= decodeURIComponent(paramStrings
[0]);
276 var value
= decodeURIComponent(paramStrings
[1]);
277 paramDict
[key
] = value
;
280 return {tabHash
: tabHash
, parameters
: paramDict
};
286 function ConstantsObserver() {}
289 * Loads all constants from |constants|. On failure, global dictionaries are
291 * @param {Object} receivedConstants The map of received constants.
293 ConstantsObserver
.prototype.onReceivedConstants = function(receivedConstants
) {
294 if (!areValidConstants(receivedConstants
))
297 Constants
= receivedConstants
;
299 EventType
= Constants
.logEventTypes
;
300 EventTypeNames
= makeInverseMap(EventType
);
301 EventPhase
= Constants
.logEventPhase
;
302 EventSourceType
= Constants
.logSourceType
;
303 EventSourceTypeNames
= makeInverseMap(EventSourceType
);
304 LogLevelType
= Constants
.logLevelType
;
305 ClientInfo
= Constants
.clientInfo
;
306 LoadFlag
= Constants
.loadFlag
;
307 NetError
= Constants
.netError
;
308 QuicError
= Constants
.quicError
;
309 QuicRstStreamError
= Constants
.quicRstStreamError
;
310 AddressFamily
= Constants
.addressFamily
;
311 LoadState
= Constants
.loadState
;
312 SdchProblemCode
= Constants
.sdchProblemCode
;
313 DataReductionProxyBypassEventType
=
314 Constants
.dataReductionProxyBypassEventType
;
315 // certStatusFlag may not be present when loading old log Files
316 if (typeof(Constants
.certStatusFlag
) == 'object')
317 CertStatusFlag
= Constants
.certStatusFlag
;
321 timeutil
.setTimeTickOffset(Constants
.timeTickOffset
);
325 * Returns true if it's given a valid-looking constants object.
326 * @param {Object} receivedConstants The received map of constants.
327 * @return {boolean} True if the |receivedConstants| object appears valid.
329 function areValidConstants(receivedConstants
) {
330 return typeof(receivedConstants
) == 'object' &&
331 typeof(receivedConstants
.logEventTypes
) == 'object' &&
332 typeof(receivedConstants
.clientInfo
) == 'object' &&
333 typeof(receivedConstants
.logEventPhase
) == 'object' &&
334 typeof(receivedConstants
.logSourceType
) == 'object' &&
335 typeof(receivedConstants
.logLevelType
) == 'object' &&
336 typeof(receivedConstants
.loadFlag
) == 'object' &&
337 typeof(receivedConstants
.netError
) == 'object' &&
338 typeof(receivedConstants
.addressFamily
) == 'object' &&
339 typeof(receivedConstants
.timeTickOffset
) == 'string' &&
340 typeof(receivedConstants
.logFormatVersion
) == 'number';
344 * Returns the name for netError.
346 * Example: netErrorToString(-105) should return
347 * "ERR_NAME_NOT_RESOLVED".
348 * @param {number} netError The net error code.
349 * @return {string} The name of the given error.
351 function netErrorToString(netError
) {
352 return getKeyWithValue(NetError
, netError
);
356 * Returns the name for quicError.
358 * Example: quicErrorToString(25) should return
360 * @param {number} quicError The QUIC error code.
361 * @return {string} The name of the given error.
363 function quicErrorToString(quicError
) {
364 return getKeyWithValue(QuicError
, quicError
);
368 * Returns the name for quicRstStreamError.
370 * Example: quicRstStreamErrorToString(3) should return
371 * "BAD_APPLICATION_PAYLOAD".
372 * @param {number} quicRstStreamError The QUIC RST_STREAM error code.
373 * @return {string} The name of the given error.
375 function quicRstStreamErrorToString(quicRstStreamError
) {
376 return getKeyWithValue(QuicRstStreamError
, quicRstStreamError
);
380 * Returns a string representation of |family|.
381 * @param {number} family An AddressFamily
382 * @return {string} A representation of the given family.
384 function addressFamilyToString(family
) {
385 var str
= getKeyWithValue(AddressFamily
, family
);
386 // All the address family start with ADDRESS_FAMILY_*.
387 // Strip that prefix since it is redundant and only clutters the output.
388 return str
.replace(/^ADDRESS_FAMILY_/, '');
392 * Returns the name for sdchProblemCode.
394 * Example: sdchProblemCodeToString(5) should return
395 * "DECODE_BODY_ERROR".
396 * @param {number} sdchProblemCode The SDCH problem code.
397 * @return {string} The name of the given problem code.
399 function sdchProblemCodeToString(sdchProblemCode
) {
400 return getKeyWithValue(SdchProblemCode
, sdchProblemCode
);