Changeset 205578 in webkit


Ignore:
Timestamp:
Sep 7, 2016 6:04:48 PM (8 years ago)
Author:
commit-queue@webkit.org
Message:

Web Inspector: Show resource timing details in Network waterfall
https://bugs.webkit.org/show_bug.cgi?id=160062

This patch adds a popover to network tab's and timeline tab's resource rows, when hovering
the recordbar. It shows times for the various parts of the resource load if they are available,
or it shows the reason for why not as text (e.g. cached resource, data URI).

Patch by Johan K. Jensen <johan_jensen@apple.com> on 2016-09-07
Reviewed by Matt Baker.

  • Localizations/en.lproj/localizedStrings.js:

Added new strings.

  • UserInterface/Main.html:

Include new files.

  • UserInterface/Views/ComputedStyleDetailsPanel.js:

(WebInspector.ComputedStyleDetailsPanel.prototype.initialLayout):
Updated to use DataGrid property to hide header.

  • UserInterface/Views/DataGrid.css:

(.data-grid.no-header > .header-wrapper):
(.data-grid.no-header > .header-wrapper > table.header): Deleted.
Hide the whole DataGrid header.

  • UserInterface/Views/DataGrid.js:

(WebInspector.DataGrid):
(WebInspector.DataGrid.prototype.get headerVisible):
(WebInspector.DataGrid.prototype.set headerVisible):
Add property to control header visibility, so grid clients aren't forced to manipulate internal grid styles.

  • UserInterface/Views/NetworkGridContentView.js:

(WebInspector.NetworkGridContentView.prototype._processPendingRecords):

  • UserInterface/Views/NetworkTimelineView.js:

(WebInspector.NetworkTimelineView.prototype._processPendingRecords):

  • UserInterface/Views/OverviewTimelineView.js:

(WebInspector.OverviewTimelineView.prototype._addResourceToDataGridIfNeeded):
Pass in new parameter for whether or not to show the popover for resources.

  • UserInterface/Views/ResourceTimelineDataGridNode.css: Added.

(.resource-timing-popover-content .data-grid):
(.resource-timing-popover-content .data-grid .graph-column > .cell-content):
(.resource-timing-popover-content .data-grid td):
(.resource-timing-popover-content .data-grid td.graph-column):
(.resource-timing-popover-content .data-grid table.data):
(.resource-timing-popover-content .data-grid tr:nth-last-child(2)):
Add styling for the popover.

  • UserInterface/Views/ResourceTimelineDataGridNode.js:

(WebInspector.ResourceTimelineDataGridNode):
(WebInspector.ResourceTimelineDataGridNode.prototype.didAddRecordBar):
(WebInspector.ResourceTimelineDataGridNode.prototype.didRemoveRecordBar):
(WebInspector.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar):
Creates the popover for a RecordBar and shows detailed info about segments.

  • UserInterface/Views/ResourceTimingPopoverDataGridNode.js: Added.

(WebInspector.ResourceTimingPopoverDataGridNode):
(WebInspector.ResourceTimingPopoverDataGridNode.prototype.get records):
(WebInspector.ResourceTimingPopoverDataGridNode.prototype.get data):
(WebInspector.ResourceTimingPopoverDataGridNode.prototype.get selectable):
(WebInspector.ResourceTimingPopoverDataGridNode.prototype.createCellContent):
DataGridNode for the popover.

  • UserInterface/Views/TimelineDataGridNode.js:

(WebInspector.TimelineDataGridNode.prototype.refreshGraph.createBar):
(WebInspector.TimelineDataGridNode.prototype.refreshGraph):
(WebInspector.TimelineDataGridNode.prototype.didAddRecordBar):
(WebInspector.TimelineDataGridNode.prototype.didRemoveRecordBar):
(WebInspector.TimelineDataGridNode):
Added hooks for notifying subclasses.

  • UserInterface/Views/TimelineRecordBar.js:

(WebInspector.TimelineRecordBar):
(WebInspector.TimelineRecordBar.fromElement):
Added symbol and static method to get the recordBar from a given element.

Location:
trunk/Source/WebInspectorUI
Files:
2 added
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebInspectorUI/ChangeLog

    r205555 r205578  
     12016-09-07  Johan K. Jensen  <johan_jensen@apple.com>
     2
     3        Web Inspector: Show resource timing details in Network waterfall
     4        https://bugs.webkit.org/show_bug.cgi?id=160062
     5
     6        This patch adds a popover to network tab's and timeline tab's resource rows, when hovering
     7        the recordbar. It shows times for the various parts of the resource load if they are available,
     8        or it shows the reason for why not as text (e.g. cached resource, data URI).
     9
     10        Reviewed by Matt Baker.
     11
     12        * Localizations/en.lproj/localizedStrings.js:
     13        Added new strings.
     14
     15        * UserInterface/Main.html:
     16        Include new files.
     17
     18        * UserInterface/Views/ComputedStyleDetailsPanel.js:
     19        (WebInspector.ComputedStyleDetailsPanel.prototype.initialLayout):
     20        Updated to use DataGrid property to hide header.
     21
     22        * UserInterface/Views/DataGrid.css:
     23        (.data-grid.no-header > .header-wrapper):
     24        (.data-grid.no-header > .header-wrapper > table.header): Deleted.
     25        Hide the whole DataGrid header.
     26
     27        * UserInterface/Views/DataGrid.js:
     28        (WebInspector.DataGrid):
     29        (WebInspector.DataGrid.prototype.get headerVisible):
     30        (WebInspector.DataGrid.prototype.set headerVisible):
     31        Add property to control header visibility, so grid clients aren't forced to manipulate internal grid styles.
     32
     33        * UserInterface/Views/NetworkGridContentView.js:
     34        (WebInspector.NetworkGridContentView.prototype._processPendingRecords):
     35        * UserInterface/Views/NetworkTimelineView.js:
     36        (WebInspector.NetworkTimelineView.prototype._processPendingRecords):
     37        * UserInterface/Views/OverviewTimelineView.js:
     38        (WebInspector.OverviewTimelineView.prototype._addResourceToDataGridIfNeeded):
     39        Pass in new parameter for whether or not to show the popover for resources.
     40
     41        * UserInterface/Views/ResourceTimelineDataGridNode.css: Added.
     42        (.resource-timing-popover-content .data-grid):
     43        (.resource-timing-popover-content .data-grid .graph-column > .cell-content):
     44        (.resource-timing-popover-content .data-grid td):
     45        (.resource-timing-popover-content .data-grid td.graph-column):
     46        (.resource-timing-popover-content .data-grid table.data):
     47        (.resource-timing-popover-content .data-grid tr:nth-last-child(2)):
     48        Add styling for the popover.
     49
     50        * UserInterface/Views/ResourceTimelineDataGridNode.js:
     51        (WebInspector.ResourceTimelineDataGridNode):
     52        (WebInspector.ResourceTimelineDataGridNode.prototype.didAddRecordBar):
     53        (WebInspector.ResourceTimelineDataGridNode.prototype.didRemoveRecordBar):
     54        (WebInspector.ResourceTimelineDataGridNode.prototype._mouseoverRecordBar):
     55        Creates the popover for a RecordBar and shows detailed info about segments.
     56
     57        * UserInterface/Views/ResourceTimingPopoverDataGridNode.js: Added.
     58        (WebInspector.ResourceTimingPopoverDataGridNode):
     59        (WebInspector.ResourceTimingPopoverDataGridNode.prototype.get records):
     60        (WebInspector.ResourceTimingPopoverDataGridNode.prototype.get data):
     61        (WebInspector.ResourceTimingPopoverDataGridNode.prototype.get selectable):
     62        (WebInspector.ResourceTimingPopoverDataGridNode.prototype.createCellContent):
     63        DataGridNode for the popover.
     64
     65        * UserInterface/Views/TimelineDataGridNode.js:
     66        (WebInspector.TimelineDataGridNode.prototype.refreshGraph.createBar):
     67        (WebInspector.TimelineDataGridNode.prototype.refreshGraph):
     68        (WebInspector.TimelineDataGridNode.prototype.didAddRecordBar):
     69        (WebInspector.TimelineDataGridNode.prototype.didRemoveRecordBar):
     70        (WebInspector.TimelineDataGridNode):
     71        Added hooks for notifying subclasses.
     72
     73        * UserInterface/Views/TimelineRecordBar.js:
     74        (WebInspector.TimelineRecordBar):
     75        (WebInspector.TimelineRecordBar.fromElement):
     76        Added symbol and static method to get the recordBar from a given element.
     77
    1782016-09-07  Devin Rousso  <dcrousso+webkit@gmail.com>
    279
  • trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js

    r205518 r205578  
    185185localizedStrings["Condition"] = "Condition";
    186186localizedStrings["Conditional expression"] = "Conditional expression";
     187localizedStrings["Connection"] = "Connection";
    187188localizedStrings["Console"] = "Console";
    188189localizedStrings["Console Evaluation"] = "Console Evaluation";
     
    214215localizedStrings["Current"] = "Current";
    215216localizedStrings["Cursor"] = "Cursor";
     217localizedStrings["DNS"] = "DNS";
    216218localizedStrings["DOM Content Loaded \u2014 %s"] = "DOM Content Loaded \u2014 %s";
    217219localizedStrings["Damping"] = "Damping";
     
    605607localizedStrings["Resource"] = "Resource";
    606608localizedStrings["Resource Type"] = "Resource Type";
     609localizedStrings["Resource failed to load."] = "Resource failed to load.";
     610localizedStrings["Resource was loaded with the 'data' scheme."] = "Resource was loaded with the 'data' scheme.";
     611localizedStrings["Resource was served from the cache."] = "Resource was served from the cache.";
    607612localizedStrings["Resources"] = "Resources";
    608613localizedStrings["Response"] = "Response";
     
    691696localizedStrings["Spread"] = "Spread";
    692697localizedStrings["Spring"] = "Spring";
     698localizedStrings["Stalled"] = "Stalled";
    693699localizedStrings["Start Playback"] = "Start Playback";
    694700localizedStrings["Start Recording"] = "Start Recording";
     
    757763localizedStrings["Total number of resources, click to show the Resources tab"] = "Total number of resources, click to show the Resources tab";
    758764localizedStrings["Total size of all resources, click to show the Network Requests timeline"] = "Total size of all resources, click to show the Network Requests timeline";
     765localizedStrings["Total time"] = "Total time";
    759766localizedStrings["Trace"] = "Trace";
    760767localizedStrings["Trace: %s"] = "Trace: %s";
  • trunk/Source/WebInspectorUI/UserInterface/Main.html

    r205418 r205578  
    137137    <link rel="stylesheet" href="Views/ResourceIcons.css">
    138138    <link rel="stylesheet" href="Views/ResourceSidebarPanel.css">
     139    <link rel="stylesheet" href="Views/ResourceTimelineDataGridNode.css">
    139140    <link rel="stylesheet" href="Views/ResourceTreeElement.css">
    140141    <link rel="stylesheet" href="Views/RulesStyleDetailsPanel.css">
     
    605606    <script src="Views/ResourceSidebarPanel.js"></script>
    606607    <script src="Views/ResourceTimelineDataGridNode.js"></script>
     608    <script src="Views/ResourceTimingPopoverDataGridNode.js"></script>
    607609    <script src="Views/RulesStyleDetailsPanel.js"></script>
    608610    <script src="Views/ScopeBar.js"></script>
  • trunk/Source/WebInspectorUI/UserInterface/Views/ComputedStyleDetailsPanel.js

    r205555 r205578  
    200200
    201201        this._containerRegionsDataGrid = new WebInspector.DOMTreeDataGrid;
    202         this._containerRegionsDataGrid.element.classList.add("no-header");
     202        this._containerRegionsDataGrid.headerVisible = false;
    203203
    204204        let containerRegionsRow = new WebInspector.DetailsSectionDataGridRow(this._containerRegionsDataGrid);
  • trunk/Source/WebInspectorUI/UserInterface/Views/DataGrid.css

    r204518 r205578  
    6767}
    6868
    69 .data-grid.no-header > .header-wrapper > table.header {
     69.data-grid.no-header > .header-wrapper {
    7070    display: none;
    7171}
  • trunk/Source/WebInspectorUI/UserInterface/Views/DataGrid.js

    r205426 r205578  
    4040        this._hiddenColumnSetting = null;
    4141        this._columnChooserEnabled = false;
     42        this._headerVisible = true;
    4243
    4344        this._rows = [];
     
    208209
    209210        return dataGrid;
     211    }
     212
     213    get headerVisible() { return this._headerVisible; }
     214
     215    set headerVisible(x)
     216    {
     217        if (x === this._headerVisible)
     218            return;
     219
     220        this._headerVisible = x;
     221        this.element.classList.toggle("no-header", !this._headerVisible);
    210222    }
    211223
  • trunk/Source/WebInspectorUI/UserInterface/Views/NetworkGridContentView.js

    r204579 r205578  
    210210
    211211            treeElement = new WebInspector.ResourceTreeElement(resourceTimelineRecord.resource);
    212             var dataGridNode = new WebInspector.ResourceTimelineDataGridNode(resourceTimelineRecord, false, this);
     212
     213            const includesGraph = false;
     214            const shouldShowPopover = true;
     215            let dataGridNode = new WebInspector.ResourceTimelineDataGridNode(resourceTimelineRecord, includesGraph, this, shouldShowPopover);
    213216
    214217            this._dataGrid.addRowInSortOrder(treeElement, dataGridNode);
  • trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTimelineView.js

    r205320 r205578  
    242242                continue;
    243243
    244             dataGridNode = new WebInspector.ResourceTimelineDataGridNode(resourceTimelineRecord, false, this);
     244            const includesGraph = false;
     245            const shouldShowPopover = true;
     246            dataGridNode = new WebInspector.ResourceTimelineDataGridNode(resourceTimelineRecord, includesGraph, this, shouldShowPopover);
    245247            this._resourceDataGridNodeMap.set(resourceTimelineRecord.resource, dataGridNode);
    246248
  • trunk/Source/WebInspectorUI/UserInterface/Views/OverviewTimelineView.js

    r205425 r205578  
    212212            resourceTimelineRecord = new WebInspector.ResourceTimelineRecord(resource);
    213213
    214         let resourceDataGridNode = new WebInspector.ResourceTimelineDataGridNode(resourceTimelineRecord, true, this);
     214        const includesGraph = true;
     215        const shouldShowPopover = false;
     216        let resourceDataGridNode = new WebInspector.ResourceTimelineDataGridNode(resourceTimelineRecord, includesGraph, this, shouldShowPopover);
    215217        this._resourceDataGridNodeMap.set(resource, resourceDataGridNode);
    216218
  • trunk/Source/WebInspectorUI/UserInterface/Views/ResourceTimelineDataGridNode.js

    r205151 r205578  
    2626WebInspector.ResourceTimelineDataGridNode = class ResourceTimelineDataGridNode extends WebInspector.TimelineDataGridNode
    2727{
    28     constructor(resourceTimelineRecord, includesGraph, graphDataSource)
     28    constructor(resourceTimelineRecord, includesGraph, graphDataSource, shouldShowPopover)
    2929    {
    3030        super(includesGraph, graphDataSource);
     
    3232        this._resource = resourceTimelineRecord.resource;
    3333        this._record = resourceTimelineRecord;
     34        this._shouldShowPopover = shouldShowPopover;
    3435
    3536        this._resource.addEventListener(WebInspector.Resource.Event.LoadingDidFinish, this._needsRefresh, this);
     
    154155    // Protected
    155156
     157    didAddRecordBar(recordBar)
     158    {
     159        if (!this._shouldShowPopover)
     160            return;
     161
     162        if (!recordBar.records.length || recordBar.records[0].type !== WebInspector.TimelineRecord.Type.Network)
     163            return;
     164
     165        console.assert(!this._mouseEnterRecordBarListener);
     166        this._mouseEnterRecordBarListener = this._mouseoverRecordBar.bind(this);
     167        recordBar.element.addEventListener("mouseenter", this._mouseEnterRecordBarListener);
     168    }
     169
     170    didRemoveRecordBar(recordBar)
     171    {
     172        if (!this._shouldShowPopover)
     173            return;
     174
     175        if (!recordBar.records.length || recordBar.records[0].type !== WebInspector.TimelineRecord.Type.Network)
     176            return;
     177
     178        recordBar.element.removeEventListener("mouseenter", this._mouseEnterRecordBarListener);
     179        this._mouseEnterRecordBarListener = null;
     180    }
     181
    156182    filterableDataForColumn(columnIdentifier)
    157183    {
     
    241267        contentElement.appendChild(this._spinner.element);
    242268    }
     269
     270    _mouseoverRecordBar(event)
     271    {
     272        let recordBar = WebInspector.TimelineRecordBar.fromElement(event.target);
     273        console.assert(recordBar);
     274        if (!recordBar)
     275            return;
     276
     277        let calculateTargetFrame = () => {
     278            let columnRect = WebInspector.Rect.rectFromClientRect(this.elementWithColumnIdentifier("graph").getBoundingClientRect());
     279            let barRect = WebInspector.Rect.rectFromClientRect(event.target.getBoundingClientRect());
     280            return columnRect.intersectionWithRect(barRect);
     281        };
     282
     283        let targetFrame = calculateTargetFrame();
     284        if (!targetFrame.size.width && !targetFrame.size.height)
     285            return;
     286
     287        console.assert(recordBar.records.length);
     288        let resource = recordBar.records[0].resource;
     289        if (!resource.timingData)
     290            return;
     291
     292        if (!resource.timingData.responseEnd)
     293            return;
     294
     295        if (this.dataGrid._dismissPopoverTimeout) {
     296            clearTimeout(this.dataGrid._dismissPopoverTimeout);
     297            this.dataGrid._dismissPopoverTimeout = undefined;
     298        }
     299
     300        let popoverContentElement = document.createElement("div");
     301        popoverContentElement.classList.add("resource-timing-popover-content");
     302
     303        if (resource.failed || resource.urlComponents.scheme === "data" || (resource.cached && resource.statusCode !== 304)) {
     304            let descriptionElement = document.createElement("span");
     305            descriptionElement.classList.add("description");
     306            if (resource.failed)
     307                descriptionElement.textContent = WebInspector.UIString("Resource failed to load.");
     308            else if (resource.urlComponents.scheme === "data")
     309                descriptionElement.textContent = WebInspector.UIString("Resource was loaded with the 'data' scheme.");
     310            else
     311                descriptionElement.textContent = WebInspector.UIString("Resource was served from the cache.");
     312            popoverContentElement.appendChild(descriptionElement);
     313        } else {
     314            let columns = {
     315                description: {
     316                    width: "80px"
     317                },
     318                graph: {
     319                    width: `${WebInspector.ResourceTimelineDataGridNode.PopoverGraphColumnWidthPixels}px`
     320                },
     321                duration: {
     322                    width: "70px",
     323                    aligned: "right"
     324                }
     325            };
     326
     327            let popoverDataGrid = new WebInspector.DataGrid(columns);
     328            popoverDataGrid.inline = true;
     329            popoverDataGrid.headerVisible = false;
     330            popoverContentElement.appendChild(popoverDataGrid.element);
     331
     332            let graphDataSource = {
     333                get secondsPerPixel() { return resource.duration / WebInspector.ResourceTimelineDataGridNode.PopoverGraphColumnWidthPixels; },
     334                get zeroTime() { return resource.firstTimestamp; },
     335                get startTime() { return resource.firstTimestamp; },
     336                get currentTime() { return this.endTime; },
     337
     338                get endTime()
     339                {
     340                    let endTimePadding = this.secondsPerPixel * WebInspector.TimelineRecordBar.MinimumWidthPixels;
     341                    return resource.lastTimestamp + endTimePadding;
     342                }
     343            };
     344
     345            let secondTimestamp = resource.timingData.domainLookupStart || resource.timingData.connectStart || resource.timingData.requestStart;
     346            if (secondTimestamp - resource.timingData.startTime)
     347                popoverDataGrid.appendChild(new WebInspector.ResourceTimingPopoverDataGridNode(WebInspector.UIString("Stalled"), resource.timingData.startTime, secondTimestamp, graphDataSource));
     348            if (resource.timingData.domainLookupStart)
     349                popoverDataGrid.appendChild(new WebInspector.ResourceTimingPopoverDataGridNode(WebInspector.UIString("DNS"), resource.timingData.domainLookupStart, resource.timingData.domainLookupEnd, graphDataSource));
     350            if (resource.timingData.connectStart)
     351                popoverDataGrid.appendChild(new WebInspector.ResourceTimingPopoverDataGridNode(WebInspector.UIString("Connection"), resource.timingData.connectStart, resource.timingData.connectEnd, graphDataSource));
     352            if (resource.timingData.secureConnectionStart)
     353                popoverDataGrid.appendChild(new WebInspector.ResourceTimingPopoverDataGridNode(WebInspector.UIString("Secure"), resource.timingData.secureConnectionStart, resource.timingData.connectEnd, graphDataSource));
     354            popoverDataGrid.appendChild(new WebInspector.ResourceTimingPopoverDataGridNode(WebInspector.UIString("Request"), resource.timingData.requestStart, resource.timingData.responseStart, graphDataSource));
     355            popoverDataGrid.appendChild(new WebInspector.ResourceTimingPopoverDataGridNode(WebInspector.UIString("Response"), resource.timingData.responseStart, resource.timingData.responseEnd, graphDataSource));
     356
     357            const higherResolution = true;
     358            let totalData = {
     359                description: WebInspector.UIString("Total time"),
     360                duration: Number.secondsToMillisecondsString(resource.timingData.responseEnd - resource.timingData.startTime, higherResolution)
     361            };
     362            popoverDataGrid.appendChild(new WebInspector.DataGridNode(totalData));
     363
     364            popoverDataGrid.updateLayout();
     365        }
     366
     367        if (!this.dataGrid._popover)
     368            this.dataGrid._popover = new WebInspector.Popover;
     369
     370        let preferredEdges = [WebInspector.RectEdge.MAX_Y, WebInspector.RectEdge.MIN_Y, WebInspector.RectEdge.MIN_X];
     371        this.dataGrid._popover.windowResizeHandler = () => {
     372            let bounds = calculateTargetFrame();
     373            this.dataGrid._popover.present(bounds.pad(2), preferredEdges);
     374        };
     375
     376        recordBar.element.addEventListener("mouseleave", () => {
     377            this.dataGrid._dismissPopoverTimeout = setTimeout(() => this.dataGrid._popover.dismiss(), WebInspector.ResourceTimelineDataGridNode.DelayedPopoverDismissalTimeout);
     378        }, {once: true});
     379
     380        this.dataGrid._popover.presentNewContentWithFrame(popoverContentElement, targetFrame.pad(2), preferredEdges);
     381    }
    243382};
     383
     384WebInspector.ResourceTimelineDataGridNode.PopoverGraphColumnWidthPixels = 110;
     385WebInspector.ResourceTimelineDataGridNode.DelayedPopoverDismissalTimeout = 500;
  • trunk/Source/WebInspectorUI/UserInterface/Views/TimelineDataGridNode.js

    r205425 r205578  
    242242            }
    243243            timelineRecordBar.refresh(this._graphDataSource);
    244             if (!timelineRecordBar.element.parentNode)
     244            if (!timelineRecordBar.element.parentNode) {
    245245                this._graphContainerElement.appendChild(timelineRecordBar.element);
     246                this.didAddRecordBar(timelineRecordBar);
     247            }
    246248            ++recordBarIndex;
    247249        }
     
    285287        // Remove the remaining unused TimelineRecordBars.
    286288        for (; recordBarIndex < this._timelineRecordBars.length; ++recordBarIndex) {
     289            this._timelineRecordBars[recordBarIndex].element.remove();
     290            this.didRemoveRecordBar(this._timelineRecordBars[recordBarIndex]);
    287291            this._timelineRecordBars[recordBarIndex].records = null;
    288             this._timelineRecordBars[recordBarIndex].element.remove();
    289292        }
    290293    }
     
    377380        return super.filterableDataForColumn(columnIdentifier);
    378381    }
     382
     383    didAddRecordBar(recordBar)
     384    {
     385        // Implemented by subclasses.
     386    }
     387
     388    didRemoveRecordBar(recordBar)
     389    {
     390        // Implemented by subclasses.
     391    }
    379392};
  • trunk/Source/WebInspectorUI/UserInterface/Views/TimelineRecordBar.js

    r203920 r205578  
    3232        this._element = document.createElement("div");
    3333        this._element.classList.add("timeline-record-bar");
     34        this._element[WebInspector.TimelineRecordBar.ElementReferenceSymbol] = this;
    3435
    3536        this.renderMode = renderMode;
     
    165166        if (!isNaN(activeStartTime))
    166167            createBarCallback(activeRecords, WebInspector.TimelineRecordBar.RenderMode.ActiveOnly);
     168    }
     169
     170    static fromElement(element)
     171    {
     172        return element[WebInspector.TimelineRecordBar.ElementReferenceSymbol] || null;
    167173    }
    168174
     
    363369};
    364370
     371WebInspector.TimelineRecordBar.ElementReferenceSymbol = Symbol("timeline-record-bar");
     372
    365373WebInspector.TimelineRecordBar.MinimumWidthPixels = 4;
    366374WebInspector.TimelineRecordBar.MinimumMarginPixels = 1;
Note: See TracChangeset for help on using the changeset viewer.