OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. | |
3 * Copyright (C) 2008, 2009 Anthony Ricaud <rik@webkit.org> | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions | |
7 * are met: | |
8 * | |
9 * 1. Redistributions of source code must retain the above copyright | |
10 * notice, this list of conditions and the following disclaimer. | |
11 * 2. Redistributions in binary form must reproduce the above copyright | |
12 * notice, this list of conditions and the following disclaimer in the | |
13 * documentation and/or other materials provided with the distribution. | |
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | |
15 * its contributors may be used to endorse or promote products derived | |
16 * from this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 */ | |
29 | |
30 WebInspector.ResourcesPanel = function() | |
31 { | |
32 WebInspector.Panel.call(this); | |
33 | |
34 this.element.addStyleClass("resources"); | |
35 | |
36 this.filterBarElement = document.createElement("div"); | |
37 this.filterBarElement.id = "resources-filter"; | |
38 this.element.appendChild(this.filterBarElement); | |
39 | |
40 this.viewsContainerElement = document.createElement("div"); | |
41 this.viewsContainerElement.id = "resource-views"; | |
42 this.element.appendChild(this.viewsContainerElement); | |
43 | |
44 this.containerElement = document.createElement("div"); | |
45 this.containerElement.id = "resources-container"; | |
46 this.containerElement.addEventListener("scroll", this._updateDividersLabelBa
rPosition.bind(this), false); | |
47 this.element.appendChild(this.containerElement); | |
48 | |
49 this.sidebarElement = document.createElement("div"); | |
50 this.sidebarElement.id = "resources-sidebar"; | |
51 this.sidebarElement.className = "sidebar"; | |
52 this.containerElement.appendChild(this.sidebarElement); | |
53 | |
54 this.sidebarResizeElement = document.createElement("div"); | |
55 this.sidebarResizeElement.className = "sidebar-resizer-vertical"; | |
56 this.sidebarResizeElement.addEventListener("mousedown", this._startSidebarDr
agging.bind(this), false); | |
57 this.element.appendChild(this.sidebarResizeElement); | |
58 | |
59 this.containerContentElement = document.createElement("div"); | |
60 this.containerContentElement.id = "resources-container-content"; | |
61 this.containerElement.appendChild(this.containerContentElement); | |
62 | |
63 this.summaryBar = new WebInspector.SummaryBar(this.categories); | |
64 this.summaryBar.element.id = "resources-summary"; | |
65 this.containerContentElement.appendChild(this.summaryBar.element); | |
66 | |
67 this.resourcesGraphsElement = document.createElement("div"); | |
68 this.resourcesGraphsElement.id = "resources-graphs"; | |
69 this.containerContentElement.appendChild(this.resourcesGraphsElement); | |
70 | |
71 this.dividersElement = document.createElement("div"); | |
72 this.dividersElement.id = "resources-dividers"; | |
73 this.containerContentElement.appendChild(this.dividersElement); | |
74 | |
75 this.eventDividersElement = document.createElement("div"); | |
76 this.eventDividersElement.id = "resources-event-dividers"; | |
77 this.containerContentElement.appendChild(this.eventDividersElement); | |
78 | |
79 this.dividersLabelBarElement = document.createElement("div"); | |
80 this.dividersLabelBarElement.id = "resources-dividers-label-bar"; | |
81 this.containerContentElement.appendChild(this.dividersLabelBarElement); | |
82 | |
83 this.sidebarTreeElement = document.createElement("ol"); | |
84 this.sidebarTreeElement.className = "sidebar-tree"; | |
85 this.sidebarElement.appendChild(this.sidebarTreeElement); | |
86 | |
87 this.sidebarTree = new TreeOutline(this.sidebarTreeElement); | |
88 | |
89 var timeGraphItem = new WebInspector.SidebarTreeElement("resources-time-grap
h-sidebar-item", WebInspector.UIString("Time")); | |
90 timeGraphItem.onselect = this._graphSelected.bind(this); | |
91 | |
92 var transferTimeCalculator = new WebInspector.ResourceTransferTimeCalculator
(); | |
93 var transferDurationCalculator = new WebInspector.ResourceTransferDurationCa
lculator(); | |
94 | |
95 timeGraphItem.sortingOptions = [ | |
96 { name: WebInspector.UIString("Sort by Start Time"), sortingFunction: We
bInspector.ResourceSidebarTreeElement.CompareByAscendingStartTime, calculator: t
ransferTimeCalculator }, | |
97 { name: WebInspector.UIString("Sort by Response Time"), sortingFunction:
WebInspector.ResourceSidebarTreeElement.CompareByAscendingResponseReceivedTime,
calculator: transferTimeCalculator }, | |
98 { name: WebInspector.UIString("Sort by End Time"), sortingFunction: WebI
nspector.ResourceSidebarTreeElement.CompareByAscendingEndTime, calculator: trans
ferTimeCalculator }, | |
99 { name: WebInspector.UIString("Sort by Duration"), sortingFunction: WebI
nspector.ResourceSidebarTreeElement.CompareByDescendingDuration, calculator: tra
nsferDurationCalculator }, | |
100 { name: WebInspector.UIString("Sort by Latency"), sortingFunction: WebIn
spector.ResourceSidebarTreeElement.CompareByDescendingLatency, calculator: trans
ferDurationCalculator }, | |
101 ]; | |
102 | |
103 timeGraphItem.selectedSortingOptionIndex = 1; | |
104 | |
105 var sizeGraphItem = new WebInspector.SidebarTreeElement("resources-size-grap
h-sidebar-item", WebInspector.UIString("Size")); | |
106 sizeGraphItem.onselect = this._graphSelected.bind(this); | |
107 | |
108 var transferSizeCalculator = new WebInspector.ResourceTransferSizeCalculator
(); | |
109 sizeGraphItem.sortingOptions = [ | |
110 { name: WebInspector.UIString("Sort by Size"), sortingFunction: WebInspe
ctor.ResourceSidebarTreeElement.CompareByDescendingSize, calculator: transferSiz
eCalculator }, | |
111 ]; | |
112 | |
113 sizeGraphItem.selectedSortingOptionIndex = 0; | |
114 | |
115 this.graphsTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspe
ctor.UIString("GRAPHS"), {}, true); | |
116 this.sidebarTree.appendChild(this.graphsTreeElement); | |
117 | |
118 this.graphsTreeElement.appendChild(timeGraphItem); | |
119 this.graphsTreeElement.appendChild(sizeGraphItem); | |
120 this.graphsTreeElement.expand(); | |
121 | |
122 this.resourcesTreeElement = new WebInspector.SidebarSectionTreeElement(WebIn
spector.UIString("RESOURCES"), {}, true); | |
123 this.sidebarTree.appendChild(this.resourcesTreeElement); | |
124 | |
125 this.resourcesTreeElement.expand(); | |
126 | |
127 var panelEnablerHeading = WebInspector.UIString("You need to enable resource
tracking to use this panel."); | |
128 var panelEnablerDisclaimer = WebInspector.UIString("Enabling resource tracki
ng will reload the page and make page loading slower."); | |
129 var panelEnablerButton = WebInspector.UIString("Enable resource tracking"); | |
130 | |
131 this.panelEnablerView = new WebInspector.PanelEnablerView("resources", panel
EnablerHeading, panelEnablerDisclaimer, panelEnablerButton); | |
132 this.panelEnablerView.addEventListener("enable clicked", this._enableResourc
eTracking, this); | |
133 | |
134 this.element.appendChild(this.panelEnablerView.element); | |
135 | |
136 this.enableToggleButton = new WebInspector.StatusBarButton("", "enable-toggl
e-status-bar-item"); | |
137 this.enableToggleButton.addEventListener("click", this._toggleResourceTracki
ng.bind(this), false); | |
138 | |
139 this.largerResourcesButton = new WebInspector.StatusBarButton(WebInspector.U
IString("Use small resource rows."), "resources-larger-resources-status-bar-item
"); | |
140 this.largerResourcesButton.toggled = Preferences.resourcesLargeRows; | |
141 this.largerResourcesButton.addEventListener("click", this._toggleLargerResou
rces.bind(this), false); | |
142 if (!Preferences.resourcesLargeRows) { | |
143 Preferences.resourcesLargeRows = !Preferences.resourcesLargeRows; | |
144 this._toggleLargerResources(); // this will toggle the preference back t
o the original | |
145 } | |
146 | |
147 this.sortingSelectElement = document.createElement("select"); | |
148 this.sortingSelectElement.className = "status-bar-item"; | |
149 this.sortingSelectElement.addEventListener("change", this._changeSortingFunc
tion.bind(this), false); | |
150 | |
151 var createFilterElement = function (category) { | |
152 var categoryElement = document.createElement("li"); | |
153 categoryElement.category = category; | |
154 categoryElement.addStyleClass(category); | |
155 var label = WebInspector.UIString("All"); | |
156 if (WebInspector.resourceCategories[category]) | |
157 label = WebInspector.resourceCategories[category].title; | |
158 categoryElement.appendChild(document.createTextNode(label)); | |
159 categoryElement.addEventListener("click", this._updateFilter.bind(this),
false); | |
160 this.filterBarElement.appendChild(categoryElement); | |
161 return categoryElement; | |
162 }; | |
163 | |
164 this.allElement = createFilterElement.call(this, "all"); | |
165 | |
166 // Add a divider | |
167 var dividerElement = document.createElement("div"); | |
168 dividerElement.addStyleClass("divider"); | |
169 this.filterBarElement.appendChild(dividerElement); | |
170 | |
171 this.filter(this.allElement); | |
172 for (var category in this.categories) | |
173 createFilterElement.call(this, category); | |
174 | |
175 this.reset(); | |
176 | |
177 timeGraphItem.select(); | |
178 } | |
179 | |
180 WebInspector.ResourcesPanel.prototype = { | |
181 toolbarItemClass: "resources", | |
182 | |
183 get categories() | |
184 { | |
185 if (!this._categories) { | |
186 this._categories = {documents: {color: {r: 47, g: 102, b: 236}}, sty
lesheets: {color: {r: 157, g: 231, b: 119}}, images: {color: {r: 164, g: 60, b:
255}}, scripts: {color: {r: 255, g: 121, b: 0}}, xhr: {color: {r: 231, g: 231, b
: 10}}, fonts: {color: {r: 255, g: 82, b: 62}}, other: {color: {r: 186, g: 186,
b: 186}}}; | |
187 for (var category in this._categories) { | |
188 this._categories[category].title = WebInspector.resourceCategori
es[category].title; | |
189 } | |
190 } | |
191 return this._categories; | |
192 }, | |
193 | |
194 filter: function (target) | |
195 { | |
196 if (target.category === "All") { | |
197 if (target.hasStyleClass("selected")) { | |
198 // We can't unselect all, so we break early here | |
199 return; | |
200 } | |
201 | |
202 // If all wasn't selected, and now is, unselect everything else. | |
203 for (var child in this.filterBarElement.childNodes) { | |
204 if (target.category !== "All") { | |
205 child.removeStyleClass("selected"); | |
206 } | |
207 | |
208 var filterClass = "filter-" + target.category; | |
209 this.resourcesGraphsElement.removeStyleClass(filterClass); | |
210 this.resourcesTreeElement.childrenListElement.removeStyleClass(f
ilterClass); | |
211 } | |
212 } else { | |
213 // Something other than all is being selected, so we want to unselec
t all | |
214 if (this.allElement.hasStyleClass("selected")) { | |
215 this.allElement.removeStyleClass("selected"); | |
216 this.resourcesGraphsElement.removeStyleClass("filter-all"); | |
217 this.resourcesTreeElement.childrenListElement.removeStyleClass("
filter-all"); | |
218 } | |
219 } | |
220 | |
221 if (target.hasStyleClass("selected")) { | |
222 target.removeStyleClass("selected"); | |
223 var filterClass = "filter-" + target.category.toLowerCase(); | |
224 | |
225 this.resourcesGraphsElement.removeStyleClass(filterClass); | |
226 this.resourcesTreeElement.childrenListElement.removeStyleClass(filte
rClass); | |
227 } else { | |
228 target.addStyleClass("selected"); | |
229 var filterClass = "filter-" + target.category.toLowerCase(); | |
230 | |
231 this.resourcesGraphsElement.addStyleClass(filterClass); | |
232 this.resourcesTreeElement.childrenListElement.addStyleClass(filterCl
ass); | |
233 } | |
234 }, | |
235 | |
236 _updateFilter: function (e) | |
237 { | |
238 this.filter(e.target); | |
239 }, | |
240 | |
241 get toolbarItemLabel() | |
242 { | |
243 return WebInspector.UIString("Resources"); | |
244 }, | |
245 | |
246 get mainResourceLoadTime() | |
247 { | |
248 return this._mainResourceLoadTime || -1; | |
249 }, | |
250 | |
251 set mainResourceLoadTime(x) | |
252 { | |
253 if (this._mainResourceLoadTime === x) | |
254 return; | |
255 | |
256 this._mainResourceLoadTime = x; | |
257 | |
258 // Update the dividers to draw the new line | |
259 this._updateGraphDividersIfNeeded(true); | |
260 }, | |
261 | |
262 get mainResourceDOMContentTime() | |
263 { | |
264 return this._mainResourceDOMContentTime || -1; | |
265 }, | |
266 | |
267 set mainResourceDOMContentTime(x) | |
268 { | |
269 if (this._mainResourceDOMContentTime === x) | |
270 return; | |
271 | |
272 this._mainResourceDOMContentTime = x; | |
273 | |
274 this._updateGraphDividersIfNeeded(true); | |
275 }, | |
276 | |
277 get statusBarItems() | |
278 { | |
279 return [this.enableToggleButton.element, this.largerResourcesButton.elem
ent, this.sortingSelectElement]; | |
280 }, | |
281 | |
282 show: function() | |
283 { | |
284 WebInspector.Panel.prototype.show.call(this); | |
285 | |
286 this._updateDividersLabelBarPosition(); | |
287 this._updateSidebarWidth(); | |
288 this.refreshIfNeeded(); | |
289 | |
290 var visibleView = this.visibleView; | |
291 if (visibleView) { | |
292 visibleView.headersVisible = true; | |
293 visibleView.show(this.viewsContainerElement); | |
294 } | |
295 | |
296 // Hide any views that are visible that are not this panel's current vis
ible view. | |
297 // This can happen when a ResourceView is visible in the Scripts panel t
hen switched | |
298 // to the this panel. | |
299 var resourcesLength = this._resources.length; | |
300 for (var i = 0; i < resourcesLength; ++i) { | |
301 var resource = this._resources[i]; | |
302 var view = resource._resourcesView; | |
303 if (!view || view === visibleView) | |
304 continue; | |
305 view.visible = false; | |
306 } | |
307 }, | |
308 | |
309 resize: function() | |
310 { | |
311 this._updateGraphDividersIfNeeded(); | |
312 | |
313 var visibleView = this.visibleView; | |
314 if (visibleView && "resize" in visibleView) | |
315 visibleView.resize(); | |
316 }, | |
317 | |
318 get searchableViews() | |
319 { | |
320 var views = []; | |
321 | |
322 const visibleView = this.visibleView; | |
323 if (visibleView && visibleView.performSearch) | |
324 views.push(visibleView); | |
325 | |
326 var resourcesLength = this._resources.length; | |
327 for (var i = 0; i < resourcesLength; ++i) { | |
328 var resource = this._resources[i]; | |
329 if (!resource._resourcesTreeElement) | |
330 continue; | |
331 var resourceView = this.resourceViewForResource(resource); | |
332 if (!resourceView.performSearch || resourceView === visibleView) | |
333 continue; | |
334 views.push(resourceView); | |
335 } | |
336 | |
337 return views; | |
338 }, | |
339 | |
340 get searchResultsSortFunction() | |
341 { | |
342 const resourceTreeElementSortFunction = this.sortingFunction; | |
343 | |
344 function sortFuction(a, b) | |
345 { | |
346 return resourceTreeElementSortFunction(a.resource._resourcesTreeElem
ent, b.resource._resourcesTreeElement); | |
347 } | |
348 | |
349 return sortFuction; | |
350 }, | |
351 | |
352 searchMatchFound: function(view, matches) | |
353 { | |
354 view.resource._resourcesTreeElement.searchMatches = matches; | |
355 }, | |
356 | |
357 searchCanceled: function(startingNewSearch) | |
358 { | |
359 WebInspector.Panel.prototype.searchCanceled.call(this, startingNewSearch
); | |
360 | |
361 if (startingNewSearch || !this._resources) | |
362 return; | |
363 | |
364 for (var i = 0; i < this._resources.length; ++i) { | |
365 var resource = this._resources[i]; | |
366 if (resource._resourcesTreeElement) | |
367 resource._resourcesTreeElement.updateErrorsAndWarnings(); | |
368 } | |
369 }, | |
370 | |
371 performSearch: function(query) | |
372 { | |
373 for (var i = 0; i < this._resources.length; ++i) { | |
374 var resource = this._resources[i]; | |
375 if (resource._resourcesTreeElement) | |
376 resource._resourcesTreeElement.resetBubble(); | |
377 } | |
378 | |
379 WebInspector.Panel.prototype.performSearch.call(this, query); | |
380 }, | |
381 | |
382 get visibleView() | |
383 { | |
384 if (this.visibleResource) | |
385 return this.visibleResource._resourcesView; | |
386 return null; | |
387 }, | |
388 | |
389 get calculator() | |
390 { | |
391 return this._calculator; | |
392 }, | |
393 | |
394 set calculator(x) | |
395 { | |
396 if (!x || this._calculator === x) | |
397 return; | |
398 | |
399 this._calculator = x; | |
400 this._calculator.reset(); | |
401 | |
402 this._staleResources = this._resources; | |
403 this.refresh(); | |
404 }, | |
405 | |
406 get sortingFunction() | |
407 { | |
408 return this._sortingFunction; | |
409 }, | |
410 | |
411 set sortingFunction(x) | |
412 { | |
413 this._sortingFunction = x; | |
414 this._sortResourcesIfNeeded(); | |
415 }, | |
416 | |
417 get needsRefresh() | |
418 { | |
419 return this._needsRefresh; | |
420 }, | |
421 | |
422 set needsRefresh(x) | |
423 { | |
424 if (this._needsRefresh === x) | |
425 return; | |
426 | |
427 this._needsRefresh = x; | |
428 | |
429 if (x) { | |
430 if (this.visible && !("_refreshTimeout" in this)) | |
431 this._refreshTimeout = setTimeout(this.refresh.bind(this), 500); | |
432 } else { | |
433 if ("_refreshTimeout" in this) { | |
434 clearTimeout(this._refreshTimeout); | |
435 delete this._refreshTimeout; | |
436 } | |
437 } | |
438 }, | |
439 | |
440 refreshIfNeeded: function() | |
441 { | |
442 if (this.needsRefresh) | |
443 this.refresh(); | |
444 }, | |
445 | |
446 refresh: function() | |
447 { | |
448 this.needsRefresh = false; | |
449 | |
450 var staleResourcesLength = this._staleResources.length; | |
451 var boundariesChanged = false; | |
452 | |
453 for (var i = 0; i < staleResourcesLength; ++i) { | |
454 var resource = this._staleResources[i]; | |
455 if (!resource._resourcesTreeElement) { | |
456 // Create the resource tree element and graph. | |
457 resource._resourcesTreeElement = new WebInspector.ResourceSideba
rTreeElement(resource); | |
458 resource._resourcesTreeElement._resourceGraph = new WebInspector
.ResourceGraph(resource); | |
459 | |
460 this.resourcesTreeElement.appendChild(resource._resourcesTreeEle
ment); | |
461 this.resourcesGraphsElement.appendChild(resource._resourcesTreeE
lement._resourceGraph.graphElement); | |
462 } | |
463 | |
464 resource._resourcesTreeElement.refresh(); | |
465 | |
466 if (this.calculator.updateBoundaries(resource)) | |
467 boundariesChanged = true; | |
468 } | |
469 | |
470 if (boundariesChanged) { | |
471 // The boundaries changed, so all resource graphs are stale. | |
472 this._staleResources = this._resources; | |
473 staleResourcesLength = this._staleResources.length; | |
474 } | |
475 | |
476 for (var i = 0; i < staleResourcesLength; ++i) | |
477 this._staleResources[i]._resourcesTreeElement._resourceGraph.refresh
(this.calculator); | |
478 | |
479 this._staleResources = []; | |
480 | |
481 this._updateGraphDividersIfNeeded(); | |
482 this._sortResourcesIfNeeded(); | |
483 this._updateSummaryGraph(); | |
484 }, | |
485 | |
486 resourceTrackingWasEnabled: function() | |
487 { | |
488 this.reset(); | |
489 }, | |
490 | |
491 resourceTrackingWasDisabled: function() | |
492 { | |
493 this.reset(); | |
494 }, | |
495 | |
496 reset: function() | |
497 { | |
498 this.closeVisibleResource(); | |
499 | |
500 this.containerElement.scrollTop = 0; | |
501 | |
502 delete this.currentQuery; | |
503 this.searchCanceled(); | |
504 | |
505 if (this._calculator) | |
506 this._calculator.reset(); | |
507 | |
508 if (this._resources) { | |
509 var resourcesLength = this._resources.length; | |
510 for (var i = 0; i < resourcesLength; ++i) { | |
511 var resource = this._resources[i]; | |
512 | |
513 resource.warnings = 0; | |
514 resource.errors = 0; | |
515 | |
516 delete resource._resourcesTreeElement; | |
517 delete resource._resourcesView; | |
518 } | |
519 } | |
520 | |
521 this._resources = []; | |
522 this._staleResources = []; | |
523 | |
524 this.mainResourceLoadTime = -1; | |
525 this.mainResourceDOMContentTime = -1; | |
526 | |
527 this.resourcesTreeElement.removeChildren(); | |
528 this.viewsContainerElement.removeChildren(); | |
529 this.resourcesGraphsElement.removeChildren(); | |
530 this.summaryBar.reset(); | |
531 | |
532 this._updateGraphDividersIfNeeded(true); | |
533 | |
534 if (InspectorController.resourceTrackingEnabled()) { | |
535 this.enableToggleButton.title = WebInspector.UIString("Resource trac
king enabled. Click to disable."); | |
536 this.enableToggleButton.toggled = true; | |
537 this.largerResourcesButton.visible = true; | |
538 this.sortingSelectElement.removeStyleClass("hidden"); | |
539 this.panelEnablerView.visible = false; | |
540 } else { | |
541 this.enableToggleButton.title = WebInspector.UIString("Resource trac
king disabled. Click to enable."); | |
542 this.enableToggleButton.toggled = false; | |
543 this.largerResourcesButton.visible = false; | |
544 this.sortingSelectElement.addStyleClass("hidden"); | |
545 this.panelEnablerView.visible = true; | |
546 } | |
547 }, | |
548 | |
549 addResource: function(resource) | |
550 { | |
551 this._resources.push(resource); | |
552 this.refreshResource(resource); | |
553 }, | |
554 | |
555 removeResource: function(resource) | |
556 { | |
557 if (this.visibleView === resource._resourcesView) | |
558 this.closeVisibleResource(); | |
559 | |
560 this._resources.remove(resource, true); | |
561 | |
562 if (resource._resourcesTreeElement) { | |
563 this.resourcesTreeElement.removeChild(resource._resourcesTreeElement
); | |
564 this.resourcesGraphsElement.removeChild(resource._resourcesTreeEleme
nt._resourceGraph.graphElement); | |
565 } | |
566 | |
567 resource.warnings = 0; | |
568 resource.errors = 0; | |
569 | |
570 delete resource._resourcesTreeElement; | |
571 delete resource._resourcesView; | |
572 | |
573 this._adjustScrollPosition(); | |
574 }, | |
575 | |
576 addMessageToResource: function(resource, msg) | |
577 { | |
578 if (!resource) | |
579 return; | |
580 | |
581 switch (msg.level) { | |
582 case WebInspector.ConsoleMessage.MessageLevel.Warning: | |
583 resource.warnings += msg.repeatDelta; | |
584 break; | |
585 case WebInspector.ConsoleMessage.MessageLevel.Error: | |
586 resource.errors += msg.repeatDelta; | |
587 break; | |
588 } | |
589 | |
590 if (!this.currentQuery && resource._resourcesTreeElement) | |
591 resource._resourcesTreeElement.updateErrorsAndWarnings(); | |
592 | |
593 var view = this.resourceViewForResource(resource); | |
594 if (view.addMessage) | |
595 view.addMessage(msg); | |
596 }, | |
597 | |
598 clearMessages: function() | |
599 { | |
600 var resourcesLength = this._resources.length; | |
601 for (var i = 0; i < resourcesLength; ++i) { | |
602 var resource = this._resources[i]; | |
603 resource.warnings = 0; | |
604 resource.errors = 0; | |
605 | |
606 if (!this.currentQuery && resource._resourcesTreeElement) | |
607 resource._resourcesTreeElement.updateErrorsAndWarnings(); | |
608 | |
609 var view = resource._resourcesView; | |
610 if (!view || !view.clearMessages) | |
611 continue; | |
612 view.clearMessages(); | |
613 } | |
614 }, | |
615 | |
616 refreshResource: function(resource) | |
617 { | |
618 this._staleResources.push(resource); | |
619 this.needsRefresh = true; | |
620 }, | |
621 | |
622 recreateViewForResourceIfNeeded: function(resource) | |
623 { | |
624 if (!resource || !resource._resourcesView) | |
625 return; | |
626 | |
627 var newView = this._createResourceView(resource); | |
628 if (newView.prototype === resource._resourcesView.prototype) | |
629 return; | |
630 | |
631 resource.warnings = 0; | |
632 resource.errors = 0; | |
633 | |
634 if (!this.currentQuery && resource._resourcesTreeElement) | |
635 resource._resourcesTreeElement.updateErrorsAndWarnings(); | |
636 | |
637 var oldView = resource._resourcesView; | |
638 | |
639 resource._resourcesView.detach(); | |
640 delete resource._resourcesView; | |
641 | |
642 resource._resourcesView = newView; | |
643 | |
644 newView.headersVisible = oldView.headersVisible; | |
645 | |
646 if (oldView.visible && oldView.element.parentNode) | |
647 newView.show(oldView.element.parentNode); | |
648 }, | |
649 | |
650 showResource: function(resource, line) | |
651 { | |
652 if (!resource) | |
653 return; | |
654 | |
655 this.containerElement.addStyleClass("viewing-resource"); | |
656 | |
657 if (this.visibleResource && this.visibleResource._resourcesView) | |
658 this.visibleResource._resourcesView.hide(); | |
659 | |
660 var view = this.resourceViewForResource(resource); | |
661 view.headersVisible = true; | |
662 view.show(this.viewsContainerElement); | |
663 | |
664 if (line) { | |
665 if (view.revealLine) | |
666 view.revealLine(line); | |
667 if (view.highlightLine) | |
668 view.highlightLine(line); | |
669 } | |
670 | |
671 if (resource._resourcesTreeElement) { | |
672 resource._resourcesTreeElement.reveal(); | |
673 resource._resourcesTreeElement.select(true); | |
674 } | |
675 | |
676 this.visibleResource = resource; | |
677 | |
678 this._updateSidebarWidth(); | |
679 }, | |
680 | |
681 showView: function(view) | |
682 { | |
683 if (!view) | |
684 return; | |
685 this.showResource(view.resource); | |
686 }, | |
687 | |
688 closeVisibleResource: function() | |
689 { | |
690 this.containerElement.removeStyleClass("viewing-resource"); | |
691 this._updateDividersLabelBarPosition(); | |
692 | |
693 if (this.visibleResource && this.visibleResource._resourcesView) | |
694 this.visibleResource._resourcesView.hide(); | |
695 delete this.visibleResource; | |
696 | |
697 if (this._lastSelectedGraphTreeElement) | |
698 this._lastSelectedGraphTreeElement.select(true); | |
699 | |
700 this._updateSidebarWidth(); | |
701 }, | |
702 | |
703 resourceViewForResource: function(resource) | |
704 { | |
705 if (!resource) | |
706 return null; | |
707 if (!resource._resourcesView) | |
708 resource._resourcesView = this._createResourceView(resource); | |
709 return resource._resourcesView; | |
710 }, | |
711 | |
712 sourceFrameForResource: function(resource) | |
713 { | |
714 var view = this.resourceViewForResource(resource); | |
715 if (!view) | |
716 return null; | |
717 | |
718 if (!view.setupSourceFrameIfNeeded) | |
719 return null; | |
720 | |
721 // Setting up the source frame requires that we be attached. | |
722 if (!this.element.parentNode) | |
723 this.attach(); | |
724 | |
725 view.setupSourceFrameIfNeeded(); | |
726 return view.sourceFrame; | |
727 }, | |
728 | |
729 handleKeyEvent: function(event) | |
730 { | |
731 this.sidebarTree.handleKeyEvent(event); | |
732 }, | |
733 | |
734 _sortResourcesIfNeeded: function() | |
735 { | |
736 var sortedElements = [].concat(this.resourcesTreeElement.children); | |
737 sortedElements.sort(this.sortingFunction); | |
738 | |
739 var sortedElementsLength = sortedElements.length; | |
740 for (var i = 0; i < sortedElementsLength; ++i) { | |
741 var treeElement = sortedElements[i]; | |
742 if (treeElement === this.resourcesTreeElement.children[i]) | |
743 continue; | |
744 | |
745 var wasSelected = treeElement.selected; | |
746 this.resourcesTreeElement.removeChild(treeElement); | |
747 this.resourcesTreeElement.insertChild(treeElement, i); | |
748 if (wasSelected) | |
749 treeElement.select(true); | |
750 | |
751 var graphElement = treeElement._resourceGraph.graphElement; | |
752 this.resourcesGraphsElement.insertBefore(graphElement, this.resource
sGraphsElement.children[i]); | |
753 } | |
754 }, | |
755 | |
756 _updateGraphDividersIfNeeded: function(force) | |
757 { | |
758 if (!this.visible) { | |
759 this.needsRefresh = true; | |
760 return; | |
761 } | |
762 | |
763 if (document.body.offsetWidth <= 0) { | |
764 // The stylesheet hasn't loaded yet or the window is closed, | |
765 // so we can't calculate what is need. Return early. | |
766 return; | |
767 } | |
768 | |
769 var dividerCount = Math.round(this.dividersElement.offsetWidth / 64); | |
770 var slice = this.calculator.boundarySpan / dividerCount; | |
771 if (!force && this._currentDividerSlice === slice) | |
772 return; | |
773 | |
774 this._currentDividerSlice = slice; | |
775 | |
776 this.dividersElement.removeChildren(); | |
777 this.eventDividersElement.removeChildren(); | |
778 this.dividersLabelBarElement.removeChildren(); | |
779 | |
780 for (var i = 1; i <= dividerCount; ++i) { | |
781 var divider = document.createElement("div"); | |
782 divider.className = "resources-divider"; | |
783 if (i === dividerCount) | |
784 divider.addStyleClass("last"); | |
785 divider.style.left = ((i / dividerCount) * 100) + "%"; | |
786 | |
787 this.dividersElement.appendChild(divider.cloneNode()); | |
788 | |
789 var label = document.createElement("div"); | |
790 label.className = "resources-divider-label"; | |
791 if (!isNaN(slice)) | |
792 label.textContent = this.calculator.formatValue(slice * i); | |
793 divider.appendChild(label); | |
794 | |
795 this.dividersLabelBarElement.appendChild(divider); | |
796 } | |
797 | |
798 if (this.calculator.startAtZero || !this.calculator.computePercentageFro
mEventTime) { | |
799 // If our current sorting method starts at zero, that means it shows
all | |
800 // resources starting at the same point, and so onLoad event and DOM
Content | |
801 // event lines really wouldn't make much sense here, so don't render
them. | |
802 // Additionally, if the calculator doesn't have the computePercentag
eFromEventTime | |
803 // function defined, we are probably sorting by size, and event time
s aren't relevant | |
804 // in this case. | |
805 return; | |
806 } | |
807 | |
808 if (this.mainResourceLoadTime !== -1) { | |
809 var percent = this.calculator.computePercentageFromEventTime(this.ma
inResourceLoadTime); | |
810 | |
811 var loadDivider = document.createElement("div"); | |
812 loadDivider.className = "resources-onload-divider"; | |
813 | |
814 var loadDividerPadding = document.createElement("div"); | |
815 loadDividerPadding.className = "resources-event-divider-padding"; | |
816 loadDividerPadding.style.left = percent + "%"; | |
817 loadDividerPadding.title = WebInspector.UIString("Load event fired")
; | |
818 loadDividerPadding.appendChild(loadDivider); | |
819 | |
820 this.eventDividersElement.appendChild(loadDividerPadding); | |
821 } | |
822 | |
823 if (this.mainResourceDOMContentTime !== -1) { | |
824 var percent = this.calculator.computePercentageFromEventTime(this.ma
inResourceDOMContentTime); | |
825 | |
826 var domContentDivider = document.createElement("div"); | |
827 domContentDivider.className = "resources-ondomcontent-divider"; | |
828 | |
829 var domContentDividerPadding = document.createElement("div"); | |
830 domContentDividerPadding.className = "resources-event-divider-paddin
g"; | |
831 domContentDividerPadding.style.left = percent + "%"; | |
832 domContentDividerPadding.title = WebInspector.UIString("DOMContent e
vent fired"); | |
833 domContentDividerPadding.appendChild(domContentDivider); | |
834 | |
835 this.eventDividersElement.appendChild(domContentDividerPadding); | |
836 } | |
837 }, | |
838 | |
839 _updateSummaryGraph: function() | |
840 { | |
841 this.summaryBar.update(this._resources); | |
842 }, | |
843 | |
844 _updateDividersLabelBarPosition: function() | |
845 { | |
846 var scrollTop = this.containerElement.scrollTop; | |
847 var dividersTop = (scrollTop < this.summaryBar.element.offsetHeight ? th
is.summaryBar.element.offsetHeight : scrollTop); | |
848 this.dividersElement.style.top = scrollTop + "px"; | |
849 this.eventDividersElement.style.top = scrollTop + "px"; | |
850 this.dividersLabelBarElement.style.top = dividersTop + "px"; | |
851 }, | |
852 | |
853 _graphSelected: function(treeElement) | |
854 { | |
855 if (this._lastSelectedGraphTreeElement) | |
856 this._lastSelectedGraphTreeElement.selectedSortingOptionIndex = this
.sortingSelectElement.selectedIndex; | |
857 | |
858 this._lastSelectedGraphTreeElement = treeElement; | |
859 | |
860 this.sortingSelectElement.removeChildren(); | |
861 for (var i = 0; i < treeElement.sortingOptions.length; ++i) { | |
862 var sortingOption = treeElement.sortingOptions[i]; | |
863 var option = document.createElement("option"); | |
864 option.label = sortingOption.name; | |
865 option.sortingFunction = sortingOption.sortingFunction; | |
866 option.calculator = sortingOption.calculator; | |
867 this.sortingSelectElement.appendChild(option); | |
868 } | |
869 | |
870 this.sortingSelectElement.selectedIndex = treeElement.selectedSortingOpt
ionIndex; | |
871 this._changeSortingFunction(); | |
872 | |
873 this.closeVisibleResource(); | |
874 this.containerElement.scrollTop = 0; | |
875 }, | |
876 | |
877 _toggleLargerResources: function() | |
878 { | |
879 if (!this.resourcesTreeElement._childrenListNode) | |
880 return; | |
881 | |
882 this.resourcesTreeElement.smallChildren = !this.resourcesTreeElement.sma
llChildren; | |
883 Preferences.resourcesLargeRows = !Preferences.resourcesLargeRows; | |
884 InspectorController.setSetting("resources-large-rows", Preferences.resou
rcesLargeRows); | |
885 | |
886 if (this.resourcesTreeElement.smallChildren) { | |
887 this.resourcesGraphsElement.addStyleClass("small"); | |
888 this.largerResourcesButton.title = WebInspector.UIString("Use large
resource rows."); | |
889 this.largerResourcesButton.toggled = false; | |
890 this._adjustScrollPosition(); | |
891 } else { | |
892 this.resourcesGraphsElement.removeStyleClass("small"); | |
893 this.largerResourcesButton.title = WebInspector.UIString("Use small
resource rows."); | |
894 this.largerResourcesButton.toggled = true; | |
895 } | |
896 }, | |
897 | |
898 _adjustScrollPosition: function() | |
899 { | |
900 // Prevent the container from being scrolled off the end. | |
901 if ((this.containerElement.scrollTop + this.containerElement.offsetHeigh
t) > this.sidebarElement.offsetHeight) | |
902 this.containerElement.scrollTop = (this.sidebarElement.offsetHeight
- this.containerElement.offsetHeight); | |
903 }, | |
904 | |
905 _changeSortingFunction: function() | |
906 { | |
907 var selectedOption = this.sortingSelectElement[this.sortingSelectElement
.selectedIndex]; | |
908 this.sortingFunction = selectedOption.sortingFunction; | |
909 this.calculator = this.summaryBar.calculator = selectedOption.calculator
; | |
910 }, | |
911 | |
912 _createResourceView: function(resource) | |
913 { | |
914 switch (resource.category) { | |
915 case WebInspector.resourceCategories.documents: | |
916 case WebInspector.resourceCategories.stylesheets: | |
917 case WebInspector.resourceCategories.scripts: | |
918 case WebInspector.resourceCategories.xhr: | |
919 return new WebInspector.SourceView(resource); | |
920 case WebInspector.resourceCategories.images: | |
921 return new WebInspector.ImageView(resource); | |
922 case WebInspector.resourceCategories.fonts: | |
923 return new WebInspector.FontView(resource); | |
924 default: | |
925 return new WebInspector.ResourceView(resource); | |
926 } | |
927 }, | |
928 | |
929 _startSidebarDragging: function(event) | |
930 { | |
931 WebInspector.elementDragStart(this.sidebarResizeElement, this._sidebarDr
agging.bind(this), this._endSidebarDragging.bind(this), event, "col-resize"); | |
932 }, | |
933 | |
934 _sidebarDragging: function(event) | |
935 { | |
936 this._updateSidebarWidth(event.pageX); | |
937 | |
938 event.preventDefault(); | |
939 }, | |
940 | |
941 _endSidebarDragging: function(event) | |
942 { | |
943 WebInspector.elementDragEnd(event); | |
944 }, | |
945 | |
946 _updateSidebarWidth: function(width) | |
947 { | |
948 if (this.sidebarElement.offsetWidth <= 0) { | |
949 // The stylesheet hasn't loaded yet or the window is closed, | |
950 // so we can't calculate what is need. Return early. | |
951 return; | |
952 } | |
953 | |
954 if (!("_currentSidebarWidth" in this)) | |
955 this._currentSidebarWidth = this.sidebarElement.offsetWidth; | |
956 | |
957 if (typeof width === "undefined") | |
958 width = this._currentSidebarWidth; | |
959 | |
960 width = Number.constrain(width, Preferences.minSidebarWidth, window.inne
rWidth / 2); | |
961 | |
962 this._currentSidebarWidth = width; | |
963 | |
964 if (this.visibleResource) { | |
965 this.containerElement.style.width = width + "px"; | |
966 this.sidebarElement.style.removeProperty("width"); | |
967 } else { | |
968 this.sidebarElement.style.width = width + "px"; | |
969 this.containerElement.style.removeProperty("width"); | |
970 } | |
971 | |
972 this.containerContentElement.style.left = width + "px"; | |
973 this.viewsContainerElement.style.left = width + "px"; | |
974 this.sidebarResizeElement.style.left = (width - 3) + "px"; | |
975 | |
976 this._updateGraphDividersIfNeeded(); | |
977 | |
978 var visibleView = this.visibleView; | |
979 if (visibleView && "resize" in visibleView) | |
980 visibleView.resize(); | |
981 }, | |
982 | |
983 _enableResourceTracking: function() | |
984 { | |
985 if (InspectorController.resourceTrackingEnabled()) | |
986 return; | |
987 this._toggleResourceTracking(this.panelEnablerView.alwaysEnabled); | |
988 }, | |
989 | |
990 _toggleResourceTracking: function(optionalAlways) | |
991 { | |
992 if (InspectorController.resourceTrackingEnabled()) { | |
993 this.largerResourcesButton.visible = false; | |
994 this.sortingSelectElement.visible = false; | |
995 InspectorController.disableResourceTracking(true); | |
996 } else { | |
997 this.largerResourcesButton.visible = true; | |
998 this.sortingSelectElement.visible = true; | |
999 InspectorController.enableResourceTracking(!!optionalAlways); | |
1000 } | |
1001 } | |
1002 } | |
1003 | |
1004 WebInspector.ResourcesPanel.prototype.__proto__ = WebInspector.Panel.prototype; | |
1005 | |
1006 WebInspector.ResourceCalculator = function() | |
1007 { | |
1008 } | |
1009 | |
1010 WebInspector.ResourceCalculator.prototype = { | |
1011 computeSummaryValues: function(resources) | |
1012 { | |
1013 var total = 0; | |
1014 var categoryValues = {}; | |
1015 | |
1016 var resourcesLength = resources.length; | |
1017 for (var i = 0; i < resourcesLength; ++i) { | |
1018 var resource = resources[i]; | |
1019 var value = this._value(resource); | |
1020 if (typeof value === "undefined") | |
1021 continue; | |
1022 if (!(resource.category.name in categoryValues)) | |
1023 categoryValues[resource.category.name] = 0; | |
1024 categoryValues[resource.category.name] += value; | |
1025 total += value; | |
1026 } | |
1027 | |
1028 return {categoryValues: categoryValues, total: total}; | |
1029 }, | |
1030 | |
1031 computeBarGraphPercentages: function(resource) | |
1032 { | |
1033 return {start: 0, middle: 0, end: (this._value(resource) / this.boundary
Span) * 100}; | |
1034 }, | |
1035 | |
1036 computeBarGraphLabels: function(resource) | |
1037 { | |
1038 const label = this.formatValue(this._value(resource)); | |
1039 var tooltip = label; | |
1040 if (resource.cached) | |
1041 tooltip = WebInspector.UIString("%s (from cache)", tooltip); | |
1042 return {left: label, right: label, tooltip: tooltip}; | |
1043 }, | |
1044 | |
1045 get boundarySpan() | |
1046 { | |
1047 return this.maximumBoundary - this.minimumBoundary; | |
1048 }, | |
1049 | |
1050 updateBoundaries: function(resource) | |
1051 { | |
1052 this.minimumBoundary = 0; | |
1053 | |
1054 var value = this._value(resource); | |
1055 if (typeof this.maximumBoundary === "undefined" || value > this.maximumB
oundary) { | |
1056 this.maximumBoundary = value; | |
1057 return true; | |
1058 } | |
1059 | |
1060 return false; | |
1061 }, | |
1062 | |
1063 reset: function() | |
1064 { | |
1065 delete this.minimumBoundary; | |
1066 delete this.maximumBoundary; | |
1067 }, | |
1068 | |
1069 _value: function(resource) | |
1070 { | |
1071 return 0; | |
1072 }, | |
1073 | |
1074 formatValue: function(value) | |
1075 { | |
1076 return value.toString(); | |
1077 } | |
1078 } | |
1079 | |
1080 WebInspector.ResourceTimeCalculator = function(startAtZero) | |
1081 { | |
1082 WebInspector.ResourceCalculator.call(this); | |
1083 this.startAtZero = startAtZero; | |
1084 } | |
1085 | |
1086 WebInspector.ResourceTimeCalculator.prototype = { | |
1087 computeSummaryValues: function(resources) | |
1088 { | |
1089 var resourcesByCategory = {}; | |
1090 var resourcesLength = resources.length; | |
1091 for (var i = 0; i < resourcesLength; ++i) { | |
1092 var resource = resources[i]; | |
1093 if (!(resource.category.name in resourcesByCategory)) | |
1094 resourcesByCategory[resource.category.name] = []; | |
1095 resourcesByCategory[resource.category.name].push(resource); | |
1096 } | |
1097 | |
1098 var earliestStart; | |
1099 var latestEnd; | |
1100 var categoryValues = {}; | |
1101 for (var category in resourcesByCategory) { | |
1102 resourcesByCategory[category].sort(WebInspector.Resource.CompareByTi
me); | |
1103 categoryValues[category] = 0; | |
1104 | |
1105 var segment = {start: -1, end: -1}; | |
1106 | |
1107 var categoryResources = resourcesByCategory[category]; | |
1108 var resourcesLength = categoryResources.length; | |
1109 for (var i = 0; i < resourcesLength; ++i) { | |
1110 var resource = categoryResources[i]; | |
1111 if (resource.startTime === -1 || resource.endTime === -1) | |
1112 continue; | |
1113 | |
1114 if (typeof earliestStart === "undefined") | |
1115 earliestStart = resource.startTime; | |
1116 else | |
1117 earliestStart = Math.min(earliestStart, resource.startTime); | |
1118 | |
1119 if (typeof latestEnd === "undefined") | |
1120 latestEnd = resource.endTime; | |
1121 else | |
1122 latestEnd = Math.max(latestEnd, resource.endTime); | |
1123 | |
1124 if (resource.startTime <= segment.end) { | |
1125 segment.end = Math.max(segment.end, resource.endTime); | |
1126 continue; | |
1127 } | |
1128 | |
1129 categoryValues[category] += segment.end - segment.start; | |
1130 | |
1131 segment.start = resource.startTime; | |
1132 segment.end = resource.endTime; | |
1133 } | |
1134 | |
1135 // Add the last segment | |
1136 categoryValues[category] += segment.end - segment.start; | |
1137 } | |
1138 | |
1139 return {categoryValues: categoryValues, total: latestEnd - earliestStart
}; | |
1140 }, | |
1141 | |
1142 computeBarGraphPercentages: function(resource) | |
1143 { | |
1144 if (resource.startTime !== -1) | |
1145 var start = ((resource.startTime - this.minimumBoundary) / this.boun
darySpan) * 100; | |
1146 else | |
1147 var start = 0; | |
1148 | |
1149 if (resource.responseReceivedTime !== -1) | |
1150 var middle = ((resource.responseReceivedTime - this.minimumBoundary)
/ this.boundarySpan) * 100; | |
1151 else | |
1152 var middle = (this.startAtZero ? start : 100); | |
1153 | |
1154 if (resource.endTime !== -1) | |
1155 var end = ((resource.endTime - this.minimumBoundary) / this.boundary
Span) * 100; | |
1156 else | |
1157 var end = (this.startAtZero ? middle : 100); | |
1158 | |
1159 if (this.startAtZero) { | |
1160 end -= start; | |
1161 middle -= start; | |
1162 start = 0; | |
1163 } | |
1164 | |
1165 return {start: start, middle: middle, end: end}; | |
1166 }, | |
1167 | |
1168 computePercentageFromEventTime: function(eventTime) | |
1169 { | |
1170 // This function computes a percentage in terms of the total loading tim
e | |
1171 // of a specific event. If startAtZero is set, then this is useless, and
we | |
1172 // want to return 0. | |
1173 if (eventTime !== -1 && !this.startAtZero) | |
1174 return ((eventTime - this.minimumBoundary) / this.boundarySpan) * 10
0; | |
1175 | |
1176 return 0; | |
1177 }, | |
1178 | |
1179 computeBarGraphLabels: function(resource) | |
1180 { | |
1181 var leftLabel = ""; | |
1182 if (resource.latency > 0) | |
1183 leftLabel = this.formatValue(resource.latency); | |
1184 | |
1185 var rightLabel = ""; | |
1186 if (resource.responseReceivedTime !== -1 && resource.endTime !== -1) | |
1187 rightLabel = this.formatValue(resource.endTime - resource.responseRe
ceivedTime); | |
1188 | |
1189 if (leftLabel && rightLabel) { | |
1190 var total = this.formatValue(resource.duration); | |
1191 var tooltip = WebInspector.UIString("%s latency, %s download (%s tot
al)", leftLabel, rightLabel, total); | |
1192 } else if (leftLabel) | |
1193 var tooltip = WebInspector.UIString("%s latency", leftLabel); | |
1194 else if (rightLabel) | |
1195 var tooltip = WebInspector.UIString("%s download", rightLabel); | |
1196 | |
1197 if (resource.cached) | |
1198 tooltip = WebInspector.UIString("%s (from cache)", tooltip); | |
1199 | |
1200 return {left: leftLabel, right: rightLabel, tooltip: tooltip}; | |
1201 }, | |
1202 | |
1203 updateBoundaries: function(resource) | |
1204 { | |
1205 var didChange = false; | |
1206 | |
1207 var lowerBound; | |
1208 if (this.startAtZero) | |
1209 lowerBound = 0; | |
1210 else | |
1211 lowerBound = this._lowerBound(resource); | |
1212 | |
1213 if (lowerBound !== -1 && (typeof this.minimumBoundary === "undefined" ||
lowerBound < this.minimumBoundary)) { | |
1214 this.minimumBoundary = lowerBound; | |
1215 didChange = true; | |
1216 } | |
1217 | |
1218 var upperBound = this._upperBound(resource); | |
1219 if (upperBound !== -1 && (typeof this.maximumBoundary === "undefined" ||
upperBound > this.maximumBoundary)) { | |
1220 this.maximumBoundary = upperBound; | |
1221 didChange = true; | |
1222 } | |
1223 | |
1224 return didChange; | |
1225 }, | |
1226 | |
1227 formatValue: function(value) | |
1228 { | |
1229 return Number.secondsToString(value, WebInspector.UIString.bind(WebInspe
ctor)); | |
1230 }, | |
1231 | |
1232 _lowerBound: function(resource) | |
1233 { | |
1234 return 0; | |
1235 }, | |
1236 | |
1237 _upperBound: function(resource) | |
1238 { | |
1239 return 0; | |
1240 }, | |
1241 } | |
1242 | |
1243 WebInspector.ResourceTimeCalculator.prototype.__proto__ = WebInspector.ResourceC
alculator.prototype; | |
1244 | |
1245 WebInspector.ResourceTransferTimeCalculator = function() | |
1246 { | |
1247 WebInspector.ResourceTimeCalculator.call(this, false); | |
1248 } | |
1249 | |
1250 WebInspector.ResourceTransferTimeCalculator.prototype = { | |
1251 formatValue: function(value) | |
1252 { | |
1253 return Number.secondsToString(value, WebInspector.UIString.bind(WebInspe
ctor)); | |
1254 }, | |
1255 | |
1256 _lowerBound: function(resource) | |
1257 { | |
1258 return resource.startTime; | |
1259 }, | |
1260 | |
1261 _upperBound: function(resource) | |
1262 { | |
1263 return resource.endTime; | |
1264 } | |
1265 } | |
1266 | |
1267 WebInspector.ResourceTransferTimeCalculator.prototype.__proto__ = WebInspector.R
esourceTimeCalculator.prototype; | |
1268 | |
1269 WebInspector.ResourceTransferDurationCalculator = function() | |
1270 { | |
1271 WebInspector.ResourceTimeCalculator.call(this, true); | |
1272 } | |
1273 | |
1274 WebInspector.ResourceTransferDurationCalculator.prototype = { | |
1275 formatValue: function(value) | |
1276 { | |
1277 return Number.secondsToString(value, WebInspector.UIString.bind(WebInspe
ctor)); | |
1278 }, | |
1279 | |
1280 _upperBound: function(resource) | |
1281 { | |
1282 return resource.duration; | |
1283 } | |
1284 } | |
1285 | |
1286 WebInspector.ResourceTransferDurationCalculator.prototype.__proto__ = WebInspect
or.ResourceTimeCalculator.prototype; | |
1287 | |
1288 WebInspector.ResourceTransferSizeCalculator = function() | |
1289 { | |
1290 WebInspector.ResourceCalculator.call(this); | |
1291 } | |
1292 | |
1293 WebInspector.ResourceTransferSizeCalculator.prototype = { | |
1294 _value: function(resource) | |
1295 { | |
1296 return resource.contentLength; | |
1297 }, | |
1298 | |
1299 formatValue: function(value) | |
1300 { | |
1301 return Number.bytesToString(value, WebInspector.UIString.bind(WebInspect
or)); | |
1302 } | |
1303 } | |
1304 | |
1305 WebInspector.ResourceTransferSizeCalculator.prototype.__proto__ = WebInspector.R
esourceCalculator.prototype; | |
1306 | |
1307 WebInspector.ResourceSidebarTreeElement = function(resource) | |
1308 { | |
1309 this.resource = resource; | |
1310 | |
1311 this.createIconElement(); | |
1312 | |
1313 WebInspector.SidebarTreeElement.call(this, "resource-sidebar-tree-item", "",
"", resource); | |
1314 | |
1315 this.refreshTitles(); | |
1316 } | |
1317 | |
1318 WebInspector.ResourceSidebarTreeElement.prototype = { | |
1319 onattach: function() | |
1320 { | |
1321 WebInspector.SidebarTreeElement.prototype.onattach.call(this); | |
1322 | |
1323 this._listItemNode.addStyleClass("resources-category-" + this.resource.c
ategory.name); | |
1324 this._listItemNode.draggable = true; | |
1325 | |
1326 // FIXME: should actually add handler to parent, to be resolved via | |
1327 // https://bugs.webkit.org/show_bug.cgi?id=30227 | |
1328 this._listItemNode.addEventListener("dragstart", this.ondragstart.bind(t
his), false); | |
1329 }, | |
1330 | |
1331 onselect: function() | |
1332 { | |
1333 WebInspector.panels.resources.showResource(this.resource); | |
1334 }, | |
1335 | |
1336 ondblclick: function(treeElement, event) | |
1337 { | |
1338 InjectedScriptAccess.openInInspectedWindow(this.resource.url, function()
{}); | |
1339 }, | |
1340 | |
1341 ondragstart: function(event) { | |
1342 event.dataTransfer.setData("text/plain", this.resource.url); | |
1343 event.dataTransfer.setData("text/uri-list", this.resource.url + "\r\n"); | |
1344 event.dataTransfer.effectAllowed = "copy"; | |
1345 return true; | |
1346 }, | |
1347 | |
1348 get mainTitle() | |
1349 { | |
1350 return this.resource.displayName; | |
1351 }, | |
1352 | |
1353 set mainTitle(x) | |
1354 { | |
1355 // Do nothing. | |
1356 }, | |
1357 | |
1358 get subtitle() | |
1359 { | |
1360 var subtitle = this.resource.displayDomain; | |
1361 | |
1362 if (this.resource.path && this.resource.lastPathComponent) { | |
1363 var lastPathComponentIndex = this.resource.path.lastIndexOf("/" + th
is.resource.lastPathComponent); | |
1364 if (lastPathComponentIndex != -1) | |
1365 subtitle += this.resource.path.substring(0, lastPathComponentInd
ex); | |
1366 } | |
1367 | |
1368 return subtitle; | |
1369 }, | |
1370 | |
1371 set subtitle(x) | |
1372 { | |
1373 // Do nothing. | |
1374 }, | |
1375 | |
1376 get selectable() | |
1377 { | |
1378 return WebInspector.panels.resources._filterCategory == "all" || WebInsp
ector.panels.resources._filterCategory == this.resource.category.name; | |
1379 }, | |
1380 | |
1381 createIconElement: function() | |
1382 { | |
1383 var previousIconElement = this.iconElement; | |
1384 | |
1385 if (this.resource.category === WebInspector.resourceCategories.images) { | |
1386 var previewImage = document.createElement("img"); | |
1387 previewImage.className = "image-resource-icon-preview"; | |
1388 previewImage.src = this.resource.url; | |
1389 | |
1390 this.iconElement = document.createElement("div"); | |
1391 this.iconElement.className = "icon"; | |
1392 this.iconElement.appendChild(previewImage); | |
1393 } else { | |
1394 this.iconElement = document.createElement("img"); | |
1395 this.iconElement.className = "icon"; | |
1396 } | |
1397 | |
1398 if (previousIconElement) | |
1399 previousIconElement.parentNode.replaceChild(this.iconElement, previo
usIconElement); | |
1400 }, | |
1401 | |
1402 refresh: function() | |
1403 { | |
1404 this.refreshTitles(); | |
1405 | |
1406 if (!this._listItemNode.hasStyleClass("resources-category-" + this.resou
rce.category.name)) { | |
1407 this._listItemNode.removeMatchingStyleClasses("resources-category-\\
w+"); | |
1408 this._listItemNode.addStyleClass("resources-category-" + this.resour
ce.category.name); | |
1409 | |
1410 this.createIconElement(); | |
1411 } | |
1412 }, | |
1413 | |
1414 resetBubble: function() | |
1415 { | |
1416 this.bubbleText = ""; | |
1417 this.bubbleElement.removeStyleClass("search-matches"); | |
1418 this.bubbleElement.removeStyleClass("warning"); | |
1419 this.bubbleElement.removeStyleClass("error"); | |
1420 }, | |
1421 | |
1422 set searchMatches(matches) | |
1423 { | |
1424 this.resetBubble(); | |
1425 | |
1426 if (!matches) | |
1427 return; | |
1428 | |
1429 this.bubbleText = matches; | |
1430 this.bubbleElement.addStyleClass("search-matches"); | |
1431 }, | |
1432 | |
1433 updateErrorsAndWarnings: function() | |
1434 { | |
1435 this.resetBubble(); | |
1436 | |
1437 if (this.resource.warnings || this.resource.errors) | |
1438 this.bubbleText = (this.resource.warnings + this.resource.errors); | |
1439 | |
1440 if (this.resource.warnings) | |
1441 this.bubbleElement.addStyleClass("warning"); | |
1442 | |
1443 if (this.resource.errors) | |
1444 this.bubbleElement.addStyleClass("error"); | |
1445 } | |
1446 } | |
1447 | |
1448 WebInspector.ResourceSidebarTreeElement.CompareByAscendingStartTime = function(a
, b) | |
1449 { | |
1450 return WebInspector.Resource.CompareByStartTime(a.resource, b.resource) | |
1451 || WebInspector.Resource.CompareByEndTime(a.resource, b.resource) | |
1452 || WebInspector.Resource.CompareByResponseReceivedTime(a.resource, b.res
ource); | |
1453 } | |
1454 | |
1455 WebInspector.ResourceSidebarTreeElement.CompareByAscendingResponseReceivedTime =
function(a, b) | |
1456 { | |
1457 return WebInspector.Resource.CompareByResponseReceivedTime(a.resource, b.res
ource) | |
1458 || WebInspector.Resource.CompareByStartTime(a.resource, b.resource) | |
1459 || WebInspector.Resource.CompareByEndTime(a.resource, b.resource); | |
1460 } | |
1461 | |
1462 WebInspector.ResourceSidebarTreeElement.CompareByAscendingEndTime = function(a,
b) | |
1463 { | |
1464 return WebInspector.Resource.CompareByEndTime(a.resource, b.resource) | |
1465 || WebInspector.Resource.CompareByStartTime(a.resource, b.resource) | |
1466 || WebInspector.Resource.CompareByResponseReceivedTime(a.resource, b.res
ource); | |
1467 } | |
1468 | |
1469 WebInspector.ResourceSidebarTreeElement.CompareByDescendingDuration = function(a
, b) | |
1470 { | |
1471 return -1 * WebInspector.Resource.CompareByDuration(a.resource, b.resource); | |
1472 } | |
1473 | |
1474 WebInspector.ResourceSidebarTreeElement.CompareByDescendingLatency = function(a,
b) | |
1475 { | |
1476 return -1 * WebInspector.Resource.CompareByLatency(a.resource, b.resource); | |
1477 } | |
1478 | |
1479 WebInspector.ResourceSidebarTreeElement.CompareByDescendingSize = function(a, b) | |
1480 { | |
1481 return -1 * WebInspector.Resource.CompareBySize(a.resource, b.resource); | |
1482 } | |
1483 | |
1484 WebInspector.ResourceSidebarTreeElement.prototype.__proto__ = WebInspector.Sideb
arTreeElement.prototype; | |
1485 | |
1486 WebInspector.ResourceGraph = function(resource) | |
1487 { | |
1488 this.resource = resource; | |
1489 | |
1490 this._graphElement = document.createElement("div"); | |
1491 this._graphElement.className = "resources-graph-side"; | |
1492 this._graphElement.addEventListener("mouseover", this.refreshLabelPositions.
bind(this), false); | |
1493 | |
1494 if (resource.cached) | |
1495 this._graphElement.addStyleClass("resource-cached"); | |
1496 | |
1497 this._barAreaElement = document.createElement("div"); | |
1498 this._barAreaElement.className = "resources-graph-bar-area hidden"; | |
1499 this._graphElement.appendChild(this._barAreaElement); | |
1500 | |
1501 this._barLeftElement = document.createElement("div"); | |
1502 this._barLeftElement.className = "resources-graph-bar waiting"; | |
1503 this._barAreaElement.appendChild(this._barLeftElement); | |
1504 | |
1505 this._barRightElement = document.createElement("div"); | |
1506 this._barRightElement.className = "resources-graph-bar"; | |
1507 this._barAreaElement.appendChild(this._barRightElement); | |
1508 | |
1509 this._labelLeftElement = document.createElement("div"); | |
1510 this._labelLeftElement.className = "resources-graph-label waiting"; | |
1511 this._barAreaElement.appendChild(this._labelLeftElement); | |
1512 | |
1513 this._labelRightElement = document.createElement("div"); | |
1514 this._labelRightElement.className = "resources-graph-label"; | |
1515 this._barAreaElement.appendChild(this._labelRightElement); | |
1516 | |
1517 this._graphElement.addStyleClass("resources-category-" + resource.category.n
ame); | |
1518 } | |
1519 | |
1520 WebInspector.ResourceGraph.prototype = { | |
1521 get graphElement() | |
1522 { | |
1523 return this._graphElement; | |
1524 }, | |
1525 | |
1526 refreshLabelPositions: function() | |
1527 { | |
1528 this._labelLeftElement.style.removeProperty("left"); | |
1529 this._labelLeftElement.style.removeProperty("right"); | |
1530 this._labelLeftElement.removeStyleClass("before"); | |
1531 this._labelLeftElement.removeStyleClass("hidden"); | |
1532 | |
1533 this._labelRightElement.style.removeProperty("left"); | |
1534 this._labelRightElement.style.removeProperty("right"); | |
1535 this._labelRightElement.removeStyleClass("after"); | |
1536 this._labelRightElement.removeStyleClass("hidden"); | |
1537 | |
1538 const labelPadding = 10; | |
1539 const rightBarWidth = (this._barRightElement.offsetWidth - labelPadding)
; | |
1540 const leftBarWidth = ((this._barLeftElement.offsetWidth - this._barRight
Element.offsetWidth) - labelPadding); | |
1541 | |
1542 var labelBefore = (this._labelLeftElement.offsetWidth > leftBarWidth); | |
1543 var labelAfter = (this._labelRightElement.offsetWidth > rightBarWidth); | |
1544 | |
1545 if (labelBefore) { | |
1546 if ((this._graphElement.offsetWidth * (this._percentages.start / 100
)) < (this._labelLeftElement.offsetWidth + 10)) | |
1547 this._labelLeftElement.addStyleClass("hidden"); | |
1548 this._labelLeftElement.style.setProperty("right", (100 - this._perce
ntages.start) + "%"); | |
1549 this._labelLeftElement.addStyleClass("before"); | |
1550 } else { | |
1551 this._labelLeftElement.style.setProperty("left", this._percentages.s
tart + "%"); | |
1552 this._labelLeftElement.style.setProperty("right", (100 - this._perce
ntages.middle) + "%"); | |
1553 } | |
1554 | |
1555 if (labelAfter) { | |
1556 if ((this._graphElement.offsetWidth * ((100 - this._percentages.end)
/ 100)) < (this._labelRightElement.offsetWidth + 10)) | |
1557 this._labelRightElement.addStyleClass("hidden"); | |
1558 this._labelRightElement.style.setProperty("left", this._percentages.
end + "%"); | |
1559 this._labelRightElement.addStyleClass("after"); | |
1560 } else { | |
1561 this._labelRightElement.style.setProperty("left", this._percentages.
middle + "%"); | |
1562 this._labelRightElement.style.setProperty("right", (100 - this._perc
entages.end) + "%"); | |
1563 } | |
1564 }, | |
1565 | |
1566 refresh: function(calculator) | |
1567 { | |
1568 var percentages = calculator.computeBarGraphPercentages(this.resource); | |
1569 var labels = calculator.computeBarGraphLabels(this.resource); | |
1570 | |
1571 this._percentages = percentages; | |
1572 | |
1573 this._barAreaElement.removeStyleClass("hidden"); | |
1574 | |
1575 if (!this._graphElement.hasStyleClass("resources-category-" + this.resou
rce.category.name)) { | |
1576 this._graphElement.removeMatchingStyleClasses("resources-category-\\
w+"); | |
1577 this._graphElement.addStyleClass("resources-category-" + this.resour
ce.category.name); | |
1578 } | |
1579 | |
1580 this._barLeftElement.style.setProperty("left", percentages.start + "%"); | |
1581 this._barLeftElement.style.setProperty("right", (100 - percentages.end)
+ "%"); | |
1582 | |
1583 this._barRightElement.style.setProperty("left", percentages.middle + "%"
); | |
1584 this._barRightElement.style.setProperty("right", (100 - percentages.end)
+ "%"); | |
1585 | |
1586 this._labelLeftElement.textContent = labels.left; | |
1587 this._labelRightElement.textContent = labels.right; | |
1588 | |
1589 var tooltip = (labels.tooltip || ""); | |
1590 this._barLeftElement.title = tooltip; | |
1591 this._labelLeftElement.title = tooltip; | |
1592 this._labelRightElement.title = tooltip; | |
1593 this._barRightElement.title = tooltip; | |
1594 } | |
1595 } | |
OLD | NEW |