<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[163637] trunk/Source/WebInspectorUI</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/163637">163637</a></dd>
<dt>Author</dt> <dd>bburg@apple.com</dd>
<dt>Date</dt> <dd>2014-02-07 11:49:41 -0800 (Fri, 07 Feb 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: Clean up DataGrid and add table columns incrementally
https://bugs.webkit.org/show_bug.cgi?id=128332

Reviewed by Timothy Hatcher.

Miscellaneous improvements to DataGrid to make it more maintainable.
In particular, it now uses a `Map` to store column settings, and the
construction sequence has been simplified so that it is safe to add
columns at the end of the constructor (or any later time).

DataGrid stores a bunch of settings per-column, but before this was done
by both storing properties on the provided `column` objects as well as
keeping several `columnIdentifier`-keyed maps for properties like `group`
and `hidden`.

Improve code readability by using for..of loops, destructuring assignment,
`Node.createElement`, and updating variable names. All variables that refer
to DOM nodes now have a `Element` suffix to distinguish them from model objects.

* UserInterface/DataGrid.js:
(.sortDataGrid):
(WebInpector.DataGrid): Create all DOM elements before populating columns.
Remove redundant objects for storing per-column values. Copy column settings
into a map rather than mutating the passed-in JSON-like settings data structure.

(WebInspector.DataGrid.createSortableDataGrid):
(WebInspector.DataGrid.prototype.get length):
(WebInspector.DataGrid.prototype.updateLayout):
(WebInspector.DataGrid.prototype.get scrollContainer):
(WebInspector.DataGrid.prototype.isScrolledToLastRow):
(WebInspector.DataGrid.prototype.scrollToLastRow):
(WebInspector.DataGrid.prototype._positionResizerElements):
(WebInspector.DataGrid.prototype.addCreationNode):
(WebInspector.DataGrid.prototype.):
(WebInspector.DataGrid.prototype.sortNodes):
(WebInspector.DataGrid.prototype.dataGridNodeFromPoint):
(WebInspector.DataGrid.prototype._clickInHeaderCell):
(WebInspector.DataGrid.prototype.isColumnSortColumn):
(WebInspector.DataGrid.prototype.headerTableHeader):
(WebInspector.DataGrid.prototype._copyTextForDataGridNode):
(WebInspector.DataGrid.prototype._resizerDragging):
(WebInspector.DataGridNode.prototype.createCells):
(WebInspector.DataGridNode.prototype.createCell.get var):
(WebInspector.DataGridNode.prototype.elementWithColumnIdentifier):
(WebInspector.DataGridNode.prototype._attach):
* UserInterface/TimelineDataGrid.js:
(WebInspector.TimelineDataGrid.prototype.treeElementMatchesActiveScopeFilters.scopeBar.this.columns.get scopeBar):
(WebInspector.TimelineDataGrid.prototype.treeElementMatchesActiveScopeFilters):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceDataGridjs">trunk/Source/WebInspectorUI/UserInterface/DataGrid.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceTimelineDataGridjs">trunk/Source/WebInspectorUI/UserInterface/TimelineDataGrid.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (163636 => 163637)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2014-02-07 19:43:26 UTC (rev 163636)
+++ trunk/Source/WebInspectorUI/ChangeLog        2014-02-07 19:49:41 UTC (rev 163637)
</span><span class="lines">@@ -1,3 +1,54 @@
</span><ins>+2014-02-07  Brian Burg  &lt;bburg@apple.com&gt;
+
+        Web Inspector: Clean up DataGrid and add table columns incrementally
+        https://bugs.webkit.org/show_bug.cgi?id=128332
+
+        Reviewed by Timothy Hatcher.
+
+        Miscellaneous improvements to DataGrid to make it more maintainable.
+        In particular, it now uses a `Map` to store column settings, and the
+        construction sequence has been simplified so that it is safe to add
+        columns at the end of the constructor (or any later time).
+
+        DataGrid stores a bunch of settings per-column, but before this was done
+        by both storing properties on the provided `column` objects as well as
+        keeping several `columnIdentifier`-keyed maps for properties like `group`
+        and `hidden`.
+
+        Improve code readability by using for..of loops, destructuring assignment,
+        `Node.createElement`, and updating variable names. All variables that refer
+        to DOM nodes now have a `Element` suffix to distinguish them from model objects.
+
+        * UserInterface/DataGrid.js:
+        (.sortDataGrid):
+        (WebInpector.DataGrid): Create all DOM elements before populating columns.
+        Remove redundant objects for storing per-column values. Copy column settings
+        into a map rather than mutating the passed-in JSON-like settings data structure.
+
+        (WebInspector.DataGrid.createSortableDataGrid):
+        (WebInspector.DataGrid.prototype.get length):
+        (WebInspector.DataGrid.prototype.updateLayout):
+        (WebInspector.DataGrid.prototype.get scrollContainer):
+        (WebInspector.DataGrid.prototype.isScrolledToLastRow):
+        (WebInspector.DataGrid.prototype.scrollToLastRow):
+        (WebInspector.DataGrid.prototype._positionResizerElements):
+        (WebInspector.DataGrid.prototype.addCreationNode):
+        (WebInspector.DataGrid.prototype.):
+        (WebInspector.DataGrid.prototype.sortNodes):
+        (WebInspector.DataGrid.prototype.dataGridNodeFromPoint):
+        (WebInspector.DataGrid.prototype._clickInHeaderCell):
+        (WebInspector.DataGrid.prototype.isColumnSortColumn):
+        (WebInspector.DataGrid.prototype.headerTableHeader):
+        (WebInspector.DataGrid.prototype._copyTextForDataGridNode):
+        (WebInspector.DataGrid.prototype._resizerDragging):
+        (WebInspector.DataGridNode.prototype.createCells):
+        (WebInspector.DataGridNode.prototype.createCell.get var):
+        (WebInspector.DataGridNode.prototype.elementWithColumnIdentifier):
+        (WebInspector.DataGridNode.prototype._attach):
+        * UserInterface/TimelineDataGrid.js:
+        (WebInspector.TimelineDataGrid.prototype.treeElementMatchesActiveScopeFilters.scopeBar.this.columns.get scopeBar):
+        (WebInspector.TimelineDataGrid.prototype.treeElementMatchesActiveScopeFilters):
+
</ins><span class="cx"> 2014-02-07  Mihai Tica  &lt;mitica@adobe.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [CSS Background Blending] Unprefix the -webkit-background-blend-mode property
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceDataGridjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/DataGrid.js (163636 => 163637)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/DataGrid.js        2014-02-07 19:43:26 UTC (rev 163636)
+++ trunk/Source/WebInspectorUI/UserInterface/DataGrid.js        2014-02-07 19:49:41 UTC (rev 163637)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2008, 2013 Apple Inc. All Rights Reserved.
</del><ins>+ * Copyright (C) 2008, 2013, 2014 Apple Inc. All Rights Reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -23,177 +23,82 @@
</span><span class="cx">  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</span><span class="cx">  */
</span><span class="cx"> 
</span><del>-/**
- * @constructor
- * @extends {WebInspector.Object}
- * @param {function(WebInspector.DataGridNode, number, string, string)=} editCallback
- * @param {function(WebInspector.DataGridNode)=} deleteCallback
- */
-WebInspector.DataGrid = function(columns, editCallback, deleteCallback)
</del><ins>+WebInspector.DataGrid = function(columnsData, editCallback, deleteCallback)
</ins><span class="cx"> {
</span><ins>+    this.columns = new Map;
+    this.orderedColumns = [];
+
+    for (var columnIdentifier in columnsData) {
+        columnData = new Map;
+        for (var propertyName in columnsData[columnIdentifier])
+            columnData.set(propertyName, columnsData[columnIdentifier][propertyName]);
+
+        columnData.set(&quot;ordinal&quot;, this.orderedColumns.length);
+        columnData.set(&quot;columnIdentifier&quot;, columnIdentifier);
+        this.orderedColumns.push(columnIdentifier);
+        this.columns.set(columnIdentifier, columnData);
+    }
+
+    this.children = [];
+    this.selectedNode = null;
+    this.expandNodesWhenArrowing = false;
+    this.root = true;
+    this.hasChildren = false;
+    this.expanded = true;
+    this.revealed = true;
+    this.selected = false;
+    this.dataGrid = this;
+    this.indentWidth = 15;
+    this.resizerElements = [];
+    this._columnWidthsInitialized = false;
+
</ins><span class="cx">     this.element = document.createElement(&quot;div&quot;);
</span><span class="cx">     this.element.className = &quot;data-grid&quot;;
</span><span class="cx">     this.element.tabIndex = 0;
</span><span class="cx">     this.element.addEventListener(&quot;keydown&quot;, this._keyDown.bind(this), false);
</span><span class="cx">     this.element.copyHandler = this;
</span><span class="cx"> 
</span><del>-    this._headerTable = document.createElement(&quot;table&quot;);
-    this._headerTable.className = &quot;header&quot;;
-    this._headerTableHeaders = {};
</del><ins>+    this._headerTableElement = document.createElement(&quot;table&quot;);
+    this._headerTableElement.className = &quot;header&quot;;
+    this._headerTableColumnGroupElement = this._headerTableElement.createChild(&quot;colgroup&quot;);
+    this._headerTableBodyElement = this._headerTableElement.createChild(&quot;tbody&quot;);
+    this._headerTableRowElement = this._headerTableBodyElement.createChild(&quot;tr&quot;);
</ins><span class="cx"> 
</span><del>-    this._dataTable = document.createElement(&quot;table&quot;);
-    this._dataTable.className = &quot;data&quot;;
</del><ins>+    this._headerTableCellElements = new Map;
</ins><span class="cx"> 
</span><del>-    this._dataTable.addEventListener(&quot;mousedown&quot;, this._mouseDownInDataTable.bind(this));
-    this._dataTable.addEventListener(&quot;click&quot;, this._clickInDataTable.bind(this));
</del><ins>+    this._scrollContainerElement = document.createElement(&quot;div&quot;);
+    this._scrollContainerElement.className = &quot;data-container&quot;;
</ins><span class="cx"> 
</span><del>-    this._dataTable.addEventListener(&quot;contextmenu&quot;, this._contextMenuInDataTable.bind(this), true);
</del><ins>+    this._dataTableElement = this._scrollContainerElement.createChild(&quot;table&quot;);
+    this._dataTableElement.className = &quot;data&quot;;
</ins><span class="cx"> 
</span><ins>+    this._dataTableElement.addEventListener(&quot;mousedown&quot;, this._mouseDownInDataTable.bind(this));
+    this._dataTableElement.addEventListener(&quot;click&quot;, this._clickInDataTable.bind(this));
+    this._dataTableElement.addEventListener(&quot;contextmenu&quot;, this._contextMenuInDataTable.bind(this), true);
+
</ins><span class="cx">     // FIXME: Add a createCallback which is different from editCallback and has different
</span><span class="cx">     // behavior when creating a new node.
</span><span class="cx">     if (editCallback) {
</span><del>-        this._dataTable.addEventListener(&quot;dblclick&quot;, this._ondblclick.bind(this), false);
</del><ins>+        this._dataTableElement.addEventListener(&quot;dblclick&quot;, this._ondblclick.bind(this), false);
</ins><span class="cx">         this._editCallback = editCallback;
</span><span class="cx">     }
</span><span class="cx">     if (deleteCallback)
</span><span class="cx">         this._deleteCallback = deleteCallback;
</span><span class="cx"> 
</span><del>-    this.aligned = {};
-    this.groups = {};
-    this._hiddenColumns = {};
</del><ins>+    this._dataTableColumnGroupElement = this._headerTableColumnGroupElement.cloneNode(true);
+    this._dataTableElement.appendChild(this._dataTableColumnGroupElement);
</ins><span class="cx"> 
</span><del>-    this._scrollContainer = document.createElement(&quot;div&quot;);
-    this._scrollContainer.className = &quot;data-container&quot;;
-    this._scrollContainer.appendChild(this._dataTable);
</del><ins>+    // This element is used by DataGridNodes to manipulate table rows and cells.
+    this.dataTableBodyElement = this._dataTableElement.createChild(&quot;tbody&quot;);
+    this._fillerRowElement = this.dataTableBodyElement.createChild(&quot;tr&quot;);
+    this._fillerRowElement.className = &quot;filler&quot;;
</ins><span class="cx"> 
</span><del>-    this.element.appendChild(this._headerTable);
-    this.element.appendChild(this._scrollContainer);
</del><ins>+    this.element.appendChild(this._headerTableElement);
+    this.element.appendChild(this._scrollContainerElement);
</ins><span class="cx"> 
</span><del>-    var headerRow = document.createElement(&quot;tr&quot;);
-    var columnGroup = document.createElement(&quot;colgroup&quot;);
-    this._columnCount = 0;
</del><ins>+    for (var columnIdentifier of this.orderedColumns)
+        this.addColumn(columnIdentifier);
</ins><span class="cx"> 
</span><del>-    for (var columnIdentifier in columns) {
-        var column = columns[columnIdentifier];
-        if (column.disclosure)
-            this.disclosureColumnIdentifier = columnIdentifier;
-
-        var col = document.createElement(&quot;col&quot;);
-        if (column.width)
-            col.style.width = column.width;
-        column.element = col;
-        columnGroup.appendChild(col);
-
-        var cell = document.createElement(&quot;th&quot;);
-        cell.className = columnIdentifier + &quot;-column&quot;;
-        cell.columnIdentifier = columnIdentifier;
-        if (column.aligned)
-            cell.classList.add(column.aligned);
-        this._headerTableHeaders[columnIdentifier] = cell;
-
-        var div = document.createElement(&quot;div&quot;);
-        if (column.titleDOMFragment)
-            div.appendChild(column.titleDOMFragment);
-        else
-            div.textContent = column.title || &quot;&quot;;
-        cell.appendChild(div);
-
-        if (column.sort) {
-            cell.classList.add(&quot;sort-&quot; + column.sort);
-            this._sortColumnCell = cell;
-        }
-
-        if (column.sortable) {
-            cell.addEventListener(&quot;click&quot;, this._clickInHeaderCell.bind(this), false);
-            cell.classList.add(&quot;sortable&quot;);
-        }
-
-        if (column.aligned)
-            this.aligned[columnIdentifier] = column.aligned;
-
-        if (column.group) {
-            this.groups[columnIdentifier] = column.group;
-            cell.classList.add(&quot;column-group-&quot; + column.group);
-        }
-
-        if (column.collapsesGroup) {
-            console.assert(column.group !== column.collapsesGroup);
-
-            var divider = document.createElement(&quot;div&quot;);
-            divider.className = &quot;divider&quot;;
-            cell.appendChild(divider);
-
-            var collapseDiv = document.createElement(&quot;div&quot;);
-            collapseDiv.className = &quot;collapser-button&quot;;
-            collapseDiv.title = this._collapserButtonCollapseColumnsToolTip();
-            collapseDiv.addEventListener(&quot;mouseover&quot;, this._mouseoverColumnCollapser.bind(this));
-            collapseDiv.addEventListener(&quot;mouseout&quot;, this._mouseoutColumnCollapser.bind(this));
-            collapseDiv.addEventListener(&quot;click&quot;, this._clickInColumnCollapser.bind(this));
-            cell.appendChild(collapseDiv);
-
-            cell.collapsesGroup = column.collapsesGroup;
-            cell.classList.add(&quot;collapser&quot;);
-        }
-
-        headerRow.appendChild(cell);
-
-        ++this._columnCount;
-    }
-
-    columnGroup.span = this._columnCount;
-
-    this._headerTableColumnGroup = columnGroup;
-    this._headerTable.appendChild(this._headerTableColumnGroup);
-    this.headerTableBody.appendChild(headerRow);
-
-    var fillerRow = document.createElement(&quot;tr&quot;);
-    fillerRow.className = &quot;filler&quot;;
-
-    for (var columnIdentifier in columns) {
-        var column = columns[columnIdentifier];
-        var td = document.createElement(&quot;td&quot;);
-        td.className = columnIdentifier + &quot;-column&quot;;
-        td.__columnIdentifier = columnIdentifier;
-        var group = this.groups[columnIdentifier];
-        if (group)
-            td.classList.add(&quot;column-group-&quot; + group);
-        fillerRow.appendChild(td);
-    }
-
-    this._dataTableColumnGroup = columnGroup.cloneNode(true);
-    this._dataTable.appendChild(this._dataTableColumnGroup);
-    this.dataTableBody.appendChild(fillerRow);
-
-    this.columns = columns || {};
-    this._columnsArray = [];
-
-    for (var columnIdentifier in columns) {
-        columns[columnIdentifier].ordinal = this._columnsArray.length;
-        columns[columnIdentifier].identifier = columnIdentifier;
-        this._columnsArray.push(columns[columnIdentifier]);
-    }
-
-    for (var i = 0; i &lt; this._columnsArray.length; ++i)
-        this._columnsArray[i].bodyElement = this._dataTableColumnGroup.children[i];
-
-    this.children = [];
-    this.selectedNode = null;
-    this.expandNodesWhenArrowing = false;
-    this.root = true;
-    this.hasChildren = false;
-    this.expanded = true;
-    this.revealed = true;
-    this.selected = false;
-    this.dataGrid = this;
-    this.indentWidth = 15;
-    this.resizers = [];
-    this._columnWidthsInitialized = false;
-
-    for (var columnIdentifier in columns) {
-        if (columns[columnIdentifier].hidden)
-            this._hideColumn(columnIdentifier);
-    }
-
</del><span class="cx">     this._generateSortIndicatorImagesIfNeeded();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -215,15 +120,15 @@
</span><span class="cx">     if (!numColumns)
</span><span class="cx">         return null;
</span><span class="cx"> 
</span><del>-    var columns = {};
</del><ins>+    var columnsData = {};
</ins><span class="cx"> 
</span><del>-    for (var i = 0; i &lt; columnNames.length; ++i) {
</del><ins>+    for (var columnName of columnNames) {
</ins><span class="cx">         var column = {};
</span><del>-        column.width = columnNames[i].length;
-        column.title = columnNames[i];
</del><ins>+        column.width = columnName.length;
+        column.title = columnName;
</ins><span class="cx">         column.sortable = true;
</span><span class="cx"> 
</span><del>-        columns[columnNames[i]] = column;
</del><ins>+        columnsData[columnName] = column;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     var nodes = [];
</span><span class="lines">@@ -237,10 +142,9 @@
</span><span class="cx">         nodes.push(node);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    var dataGrid = new WebInspector.DataGrid(columns);
-    var length = nodes.length;
-    for (var i = 0; i &lt; length; ++i)
-        dataGrid.appendChild(nodes[i]);
</del><ins>+    var dataGrid = new WebInspector.DataGrid(columnsData);
+    for (var node of nodes)
+        dataGrid.appendChild(node);
</ins><span class="cx"> 
</span><span class="cx">     dataGrid.addEventListener(WebInspector.DataGrid.Event.SortChanged, sortDataGrid, this);
</span><span class="cx"> 
</span><span class="lines">@@ -251,8 +155,8 @@
</span><span class="cx">         var sortDirection = dataGrid.sortOrder === &quot;ascending&quot; ? 1 : -1;
</span><span class="cx">         var columnIsNumeric = true;
</span><span class="cx"> 
</span><del>-        for (var i = 0; i &lt; nodes.length; i++) {
-            if (isNaN(Number(nodes[i].data[sortColumnIdentifier] || &quot;&quot;)))
</del><ins>+        for (var node of nodes) {
+            if (isNaN(Number(node.data[sortColumnIdentifier] || &quot;&quot;)))
</ins><span class="cx">                 columnIsNumeric = false;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -275,8 +179,8 @@
</span><span class="cx"> 
</span><span class="cx">         nodes.sort(comparator);
</span><span class="cx">         dataGrid.removeChildren();
</span><del>-        for (var i = 0; i &lt; nodes.length; i++)
-            dataGrid.appendChild(nodes[i]);
</del><ins>+        for (var node of nodes)
+            dataGrid.appendChild(node);
</ins><span class="cx">     }
</span><span class="cx">     return dataGrid;
</span><span class="cx"> }
</span><span class="lines">@@ -423,63 +327,33 @@
</span><span class="cx">         return null;
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    get headerTableBody()
-    {
-        if (&quot;_headerTableBody&quot; in this)
-            return this._headerTableBody;
-
-        this._headerTableBody = this._headerTable.getElementsByTagName(&quot;tbody&quot;)[0];
-        if (!this._headerTableBody) {
-            this._headerTableBody = this.element.ownerDocument.createElement(&quot;tbody&quot;);
-            this._headerTable.insertBefore(this._headerTableBody, this._headerTable.tFoot);
-        }
-
-        return this._headerTableBody;
-    },
-
-    get dataTableBody()
-    {
-        if (&quot;_dataTableBody&quot; in this)
-            return this._dataTableBody;
-
-        this._dataTableBody = this._dataTable.getElementsByTagName(&quot;tbody&quot;)[0];
-        if (!this._dataTableBody) {
-            this._dataTableBody = this.element.ownerDocument.createElement(&quot;tbody&quot;);
-            this._dataTable.insertBefore(this._dataTableBody, this._dataTable.tFoot);
-        }
-
-        return this._dataTableBody;
-    },
-
-    /**
-     * @param {number=} maxDescentLevel
-     */
</del><span class="cx">     autoSizeColumns: function(minPercent, maxPercent, maxDescentLevel)
</span><span class="cx">     {
</span><span class="cx">         if (minPercent)
</span><del>-            minPercent = Math.min(minPercent, Math.floor(100 / this._columnCount));
</del><ins>+            minPercent = Math.min(minPercent, Math.floor(100 / this.orderedColumns.length));
</ins><span class="cx">         var widths = {};
</span><del>-        var columns = this.columns;
-        for (var columnIdentifier in columns)
-            widths[columnIdentifier] = (columns[columnIdentifier].title || &quot;&quot;).length;
</del><ins>+        // For the first width approximation, use the character length of column titles.
+        for (var [identifier, column] of this.columns)
+            widths[identifier] = column.get(&quot;title&quot;, &quot;&quot;).length;
</ins><span class="cx"> 
</span><ins>+        // Now approximate the width of each column as max(title, cells).
</ins><span class="cx">         var children = maxDescentLevel ? this._enumerateChildren(this, [], maxDescentLevel + 1) : this.children;
</span><del>-        for (var i = 0; i &lt; children.length; ++i) {
-            var node = children[i];
-            for (var columnIdentifier in columns) {
-                var text = node.data[columnIdentifier] || &quot;&quot;;
-                if (text.length &gt; widths[columnIdentifier])
-                    widths[columnIdentifier] = text.length;
</del><ins>+        for (var node of children) {
+            for (var identifier of this.columns.keys()) {
+                var text = node.data[identifier] || &quot;&quot;;
+                if (text.length &gt; widths[identifier])
+                    widths[identifier] = text.length;
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         var totalColumnWidths = 0;
</span><del>-        for (var columnIdentifier in columns)
-            totalColumnWidths += widths[columnIdentifier];
</del><ins>+        for (var identifier of this.columns.keys())
+            totalColumnWidths += widths[identifier];
</ins><span class="cx"> 
</span><ins>+        // Compute percentages and clamp desired widths to min and max widths.
</ins><span class="cx">         var recoupPercent = 0;
</span><del>-        for (var columnIdentifier in columns) {
-            var width = Math.round(100 * widths[columnIdentifier] / totalColumnWidths);
</del><ins>+        for (var identifier of this.columns.keys()) {
+            var width = Math.round(100 * widths[identifier] / totalColumnWidths);
</ins><span class="cx">             if (minPercent &amp;&amp; width &lt; minPercent) {
</span><span class="cx">                 recoupPercent += (minPercent - width);
</span><span class="cx">                 width = minPercent;
</span><span class="lines">@@ -487,13 +361,14 @@
</span><span class="cx">                 recoupPercent -= (width - maxPercent);
</span><span class="cx">                 width = maxPercent;
</span><span class="cx">             }
</span><del>-            widths[columnIdentifier] = width;
</del><ins>+            widths[identifier] = width;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        // If we assigned too much width due to the above, reduce column widths.
</ins><span class="cx">         while (minPercent &amp;&amp; recoupPercent &gt; 0) {
</span><del>-            for (var columnIdentifier in columns) {
-                if (widths[columnIdentifier] &gt; minPercent) {
-                    --widths[columnIdentifier];
</del><ins>+            for (var identifier of this.columns.keys()) {
+                if (widths[identifier] &gt; minPercent) {
+                    --widths[identifier];
</ins><span class="cx">                     --recoupPercent;
</span><span class="cx">                     if (!recoupPercent)
</span><span class="cx">                         break;
</span><span class="lines">@@ -501,10 +376,11 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        // If extra width remains after clamping widths, expand column widths.
</ins><span class="cx">         while (maxPercent &amp;&amp; recoupPercent &lt; 0) {
</span><del>-            for (var columnIdentifier in columns) {
-                if (widths[columnIdentifier] &lt; maxPercent) {
-                    ++widths[columnIdentifier];
</del><ins>+            for (var identifier of this.columns.keys()) {
+                if (widths[identifier] &lt; maxPercent) {
+                    ++widths[identifier];
</ins><span class="cx">                     ++recoupPercent;
</span><span class="cx">                     if (!recoupPercent)
</span><span class="cx">                         break;
</span><span class="lines">@@ -512,12 +388,84 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        for (var columnIdentifier in columns)
-            columns[columnIdentifier].element.style.width = widths[columnIdentifier] + &quot;%&quot;;
</del><ins>+        for (var [identifier, column] of this.columns)
+            column.get(&quot;element&quot;).style.width = widths[identifier] + &quot;%&quot;;
</ins><span class="cx">         this._columnWidthsInitialized = false;
</span><span class="cx">         this.updateLayout();
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    addColumn: function(columnIdentifier)
+    {
+        var column = this.columns.get(columnIdentifier);
+        console.assert(column);
+
+        if (column.has(&quot;disclosure&quot;))
+            this.disclosureColumnIdentifier = columnIdentifier;
+
+        var headerColumnElement = this._headerTableColumnGroupElement.createChild(&quot;col&quot;);
+        if (column.has(&quot;width&quot;))
+            headerColumnElement.style.width = column.get(&quot;width&quot;);
+        column.set(&quot;element&quot;, headerColumnElement);
+
+        var headerCellElement = this._headerTableRowElement.createChild(&quot;th&quot;);
+        headerCellElement.className = columnIdentifier + &quot;-column&quot;;
+        headerCellElement.columnIdentifier = columnIdentifier;
+        if (column.has(&quot;aligned&quot;))
+            headerCellElement.classList.add(column.get(&quot;aligned&quot;));
+        this._headerTableCellElements.set(columnIdentifier, headerCellElement);
+
+        var div = headerCellElement.createChild(&quot;div&quot;);
+        if (column.has(&quot;titleDOMFragment&quot;))
+            div.appendChild(column.get(&quot;titleDOMFragment&quot;));
+        else
+            div.textContent = column.get(&quot;title&quot;, &quot;&quot;);
+
+        if (column.has(&quot;sort&quot;)) {
+            headerCellElement.classList.add(&quot;sort-&quot; + column.get(&quot;sort&quot;));
+            this._sortColumnCell = headerCellElement;
+        }
+
+        if (column.has(&quot;sortable&quot;)) {
+            headerCellElement.addEventListener(&quot;click&quot;, this._clickInHeaderCell.bind(this), false);
+            headerCellElement.classList.add(&quot;sortable&quot;);
+        }
+
+        if (column.has(&quot;group&quot;))
+            headerCellElement.classList.add(&quot;column-group-&quot; + column.get(&quot;group&quot;));
+
+        if (column.has(&quot;collapsesGroup&quot;)) {
+            console.assert(column.get(&quot;group&quot;) !== column.get(&quot;collapsesGroup&quot;));
+
+            var dividerElement = headerCellElement.createChild(&quot;div&quot;);
+            dividerElement.className = &quot;divider&quot;;
+
+            var collapseDiv = headerCellElement.createChild(&quot;div&quot;);
+            collapseDiv.className = &quot;collapser-button&quot;;
+            collapseDiv.title = this._collapserButtonCollapseColumnsToolTip();
+            collapseDiv.addEventListener(&quot;mouseover&quot;, this._mouseoverColumnCollapser.bind(this));
+            collapseDiv.addEventListener(&quot;mouseout&quot;, this._mouseoutColumnCollapser.bind(this));
+            collapseDiv.addEventListener(&quot;click&quot;, this._clickInColumnCollapser.bind(this));
+
+            headerCellElement.collapsesGroup = column.get(&quot;collapsesGroup&quot;);
+            headerCellElement.classList.add(&quot;collapser&quot;);
+        }
+
+        this._headerTableColumnGroupElement.span = this.orderedColumns.length;
+
+        var dataColumnElement = headerColumnElement.cloneNode();
+        this._dataTableColumnGroupElement.appendChild(dataColumnElement);
+        column.set(&quot;bodyElement&quot;, dataColumnElement);
+
+        var fillerCellElement = this._fillerRowElement.createChild(&quot;td&quot;);
+        fillerCellElement.className = columnIdentifier + &quot;-column&quot;;
+        fillerCellElement.__columnIdentifier = columnIdentifier;
+        if (column.has(&quot;group&quot;))
+            fillerCellElement.classList.add(&quot;column-group-&quot; + column.get(&quot;group&quot;));
+
+        if (column.has(&quot;hidden&quot;))
+            this._hideColumn(columnIdentifier);
+    },
+
</ins><span class="cx">     _enumerateChildren: function(rootNode, result, maxLevel)
</span><span class="cx">     {
</span><span class="cx">         if (!rootNode.root)
</span><span class="lines">@@ -547,35 +495,34 @@
</span><span class="cx">             // when the two columns that get resized get a percent value for
</span><span class="cx">             // their widths, all the other columns already have percent values
</span><span class="cx">             // for their widths.
</span><del>-            var headerTableColumns = this._headerTableColumnGroup.children;
-            var tableWidth = this._dataTable.offsetWidth;
-            var numColumns = headerTableColumns.length;
</del><ins>+            var headerTableColumnElements = this._headerTableColumnGroupElement.children;
+            var tableWidth = this._dataTableElement.offsetWidth;
+            var numColumns = headerTableColumnElements.length;
</ins><span class="cx">             for (var i = 0; i &lt; numColumns; i++) {
</span><del>-                var headerCell = this.headerTableBody.rows[0].cells[i]
-                if (this._isColumnVisible(headerCell.columnIdentifier)) {
-                    var columnWidth = headerCell.offsetWidth;
</del><ins>+                var headerCellElement = this._headerTableBodyElement.rows[0].cells[i]
+                if (this._isColumnVisible(headerCellElement.columnIdentifier)) {
+                    var columnWidth = headerCellElement.offsetWidth;
</ins><span class="cx">                     var percentWidth = ((columnWidth / tableWidth) * 100) + &quot;%&quot;;
</span><del>-                    this._headerTableColumnGroup.children[i].style.width = percentWidth;
-                    this._dataTableColumnGroup.children[i].style.width = percentWidth;
</del><ins>+                    this._headerTableColumnGroupElement.children[i].style.width = percentWidth;
+                    this._dataTableColumnGroupElement.children[i].style.width = percentWidth;
</ins><span class="cx">                 } else {
</span><del>-                    this._headerTableColumnGroup.children[i].style.width = 0;
-                    this._dataTableColumnGroup.children[i].style.width = 0;
</del><ins>+                    this._headerTableColumnGroupElement.children[i].style.width = 0;
+                    this._dataTableColumnGroupElement.children[i].style.width = 0;
</ins><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             this._columnWidthsInitialized = true;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        this._positionResizers();
</del><ins>+        this._positionResizerElements();
</ins><span class="cx">         this.dispatchEventToListeners(WebInspector.DataGrid.Event.DidLayout);
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     columnWidthsMap: function()
</span><span class="cx">     {
</span><span class="cx">         var result = {};
</span><del>-        for (var columnIdentifier in this.columns) {
-            var column = this.columns[columnIdentifier];
-            var width = this._headerTableColumnGroup.children[column.ordinal].style.width;
</del><ins>+        for (var [identifier, column] of this.columns) {
+            var width = this._headerTableColumnGroupElement.children[column.get(&quot;ordinal&quot;)].style.width;
</ins><span class="cx">             result[columnIdentifier] = parseFloat(width);
</span><span class="cx">         }
</span><span class="cx">         return result;
</span><span class="lines">@@ -583,11 +530,11 @@
</span><span class="cx"> 
</span><span class="cx">     applyColumnWidthsMap: function(columnWidthsMap)
</span><span class="cx">     {
</span><del>-        for (var columnIdentifier in this.columns) {
-            var column = this.columns[columnIdentifier];
-            var width = (columnWidthsMap[columnIdentifier] || 0) + &quot;%&quot;;
-            this._headerTableColumnGroup.children[column.ordinal].style.width = width;
-            this._dataTableColumnGroup.children[column.ordinal].style.width = width;
</del><ins>+        for (var [identifier, column] of this.columns) {
+            var width = (columnWidthsMap[identifier] || 0) + &quot;%&quot;;
+            var ordinal = column.get(&quot;ordinal&quot;);
+            this._headerTableColumnGroupElement.children[ordinal].style.width = width;
+            this._dataTableColumnGroupElement.children[ordinal].style.width = width;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         this.updateLayout();
</span><span class="lines">@@ -595,86 +542,80 @@
</span><span class="cx"> 
</span><span class="cx">     _isColumnVisible: function(columnIdentifier)
</span><span class="cx">     {
</span><del>-        return !(columnIdentifier in this._hiddenColumns);
</del><ins>+        return !this.columns.get(columnIdentifier).has(&quot;hidden&quot;);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     _showColumn: function(columnIdentifier)
</span><span class="cx">     {
</span><del>-        delete this._hiddenColumns[columnIdentifier];
</del><ins>+        this.columns.get(columnIdentifier).delete(&quot;hidden&quot;);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     _hideColumn: function(columnIdentifier)
</span><span class="cx">     {
</span><del>-        this._hiddenColumns[columnIdentifier] = true;
</del><ins>+        var column = this.columns.get(columnIdentifier);
+        column.set(&quot;hidden&quot;, true);
</ins><span class="cx"> 
</span><del>-        var column = this.columns[columnIdentifier];
-        var columnElement = column.element;
</del><ins>+        var columnElement = column.get(&quot;element&quot;);
</ins><span class="cx">         columnElement.style.width = 0;
</span><span class="cx"> 
</span><del>-        var columnBodyElement = column.bodyElement;
-        columnBodyElement.style.width = 0;
-
</del><span class="cx">         this._columnWidthsInitialized = false;
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     get scrollContainer()
</span><span class="cx">     {
</span><del>-        return this._scrollContainer;
</del><ins>+        return this._scrollContainerElement;
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     isScrolledToLastRow: function()
</span><span class="cx">     {
</span><del>-        return this._scrollContainer.isScrolledToBottom();
</del><ins>+        return this._scrollContainerElement.isScrolledToBottom();
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     scrollToLastRow: function()
</span><span class="cx">     {
</span><del>-        this._scrollContainer.scrollTop = this._scrollContainer.scrollHeight - this._scrollContainer.offsetHeight;
</del><ins>+        this._scrollContainerElement.scrollTop = this._scrollContainerElement.scrollHeight - this._scrollContainerElement.offsetHeight;
</ins><span class="cx">     },
</span><span class="cx"> 
</span><del>-    _positionResizers: function()
</del><ins>+    _positionResizerElements: function()
</ins><span class="cx">     {
</span><del>-        var headerTableColumns = this._headerTableColumnGroup.children;
-        var numColumns = headerTableColumns.length;
</del><span class="cx">         var left = 0;
</span><del>-        var previousResizer = null;
</del><ins>+        var previousResizerElement = null;
</ins><span class="cx"> 
</span><span class="cx">         // Make n - 1 resizers for n columns.
</span><del>-        for (var i = 0; i &lt; numColumns - 1; i++) {
-            var resizer = this.resizers[i];
</del><ins>+        for (var i = 0; i &lt; this.orderedColumns.length - 1; ++i) {
+            var resizerElement = this.resizerElements[i];
</ins><span class="cx"> 
</span><del>-            if (!resizer) {
</del><ins>+            if (!resizerElement) {
</ins><span class="cx">                 // This is the first call to updateWidth, so the resizers need
</span><span class="cx">                 // to be created.
</span><del>-                resizer = document.createElement(&quot;div&quot;);
-                resizer.classList.add(&quot;data-grid-resizer&quot;);
</del><ins>+                resizerElement = document.createElement(&quot;div&quot;);
+                resizerElement.classList.add(&quot;data-grid-resizer&quot;);
</ins><span class="cx">                 // This resizer is associated with the column to its right.
</span><del>-                resizer.addEventListener(&quot;mousedown&quot;, this._startResizerDragging.bind(this), false);
-                this.element.appendChild(resizer);
-                this.resizers[i] = resizer;
</del><ins>+                resizerElement.addEventListener(&quot;mousedown&quot;, this._startResizerDragging.bind(this), false);
+                this.element.appendChild(resizerElement);
+                this.resizerElements[i] = resizerElement;
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             // Get the width of the cell in the first (and only) row of the
</span><span class="cx">             // header table in order to determine the width of the column, since
</span><span class="cx">             // it is not possible to query a column for its width.
</span><del>-            left += this.headerTableBody.rows[0].cells[i].offsetWidth;
</del><ins>+            left += this._headerTableBodyElement.rows[0].cells[i].offsetWidth;
</ins><span class="cx"> 
</span><del>-            var columnIsVisible = this._isColumnVisible(this._columnsArray[i].identifier);
-            if (columnIsVisible) {
-                resizer.style.removeProperty(&quot;display&quot;);
-                resizer.style.left = left + &quot;px&quot;;
-                resizer.leftNeighboringColumnID = i;
-                if (previousResizer)
-                    previousResizer.rightNeighboringColumnID = i;
-                previousResizer = resizer;
</del><ins>+            if (this._isColumnVisible(this.orderedColumns[i])) {
+                resizerElement.style.removeProperty(&quot;display&quot;);
+                resizerElement.style.left = left + &quot;px&quot;;
+                resizerElement.leftNeighboringColumnID = i;
+                if (previousResizerElement)
+                    previousResizerElement.rightNeighboringColumnID = i;
+                previousResizerElement = resizerElement;
</ins><span class="cx">             } else {
</span><del>-                resizer.style.setProperty(&quot;display&quot;, &quot;none&quot;);
-                resizer.leftNeighboringColumnID = 0;
-                resizer.rightNeighboringColumnID = 0;
</del><ins>+                resizerElement.style.setProperty(&quot;display&quot;, &quot;none&quot;);
+                resizerElement.leftNeighboringColumnID = 0;
+                resizerElement.rightNeighboringColumnID = 0;
</ins><span class="cx">             }
</span><span class="cx">         }
</span><del>-        if (previousResizer)
-            previousResizer.rightNeighboringColumnID = numColumns - 1;
</del><ins>+        if (previousResizerElement)
+            previousResizerElement.rightNeighboringColumnID = this.orderedColumns.length - 1;
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     addCreationNode: function(hasChildren)
</span><span class="lines">@@ -683,8 +624,8 @@
</span><span class="cx">             this.creationNode.makeNormal();
</span><span class="cx"> 
</span><span class="cx">         var emptyData = {};
</span><del>-        for (var column in this.columns)
-            emptyData[column] = '';
</del><ins>+        for (var identifier of this.columns.keys())
+            emptyData[identifier] = '';
</ins><span class="cx">         this.creationNode = new WebInspector.CreationDataGridNode(emptyData, hasChildren);
</span><span class="cx">         this.appendChild(this.creationNode);
</span><span class="cx">     },
</span><span class="lines">@@ -811,12 +752,12 @@
</span><span class="cx">             if (b._dataGridNode._data.summaryRow)
</span><span class="cx">                 return -1;
</span><span class="cx"> 
</span><del>-            var aDataGirdNode = a._dataGridNode;
-            var bDataGirdNode = b._dataGridNode;
-            return reverseMode ? comparator(bDataGirdNode, aDataGirdNode) : comparator(aDataGirdNode, bDataGirdNode);
</del><ins>+            var aDataGridNode = a._dataGridNode;
+            var bDataGridNode = b._dataGridNode;
+            return reverseMode ? comparator(bDataGridNode, aDataGridNode) : comparator(aDataGridNode, bDataGridNode);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        var tbody = this.dataTableBody;
</del><ins>+        var tbody = this.dataTableBodyElement;
</ins><span class="cx">         var tbodyParent = tbody.parentElement;
</span><span class="cx">         tbodyParent.removeChild(tbody);
</span><span class="cx"> 
</span><span class="lines">@@ -944,7 +885,7 @@
</span><span class="cx"> 
</span><span class="cx">     dataGridNodeFromPoint: function(x, y)
</span><span class="cx">     {
</span><del>-        var node = this._dataTable.ownerDocument.elementFromPoint(x, y);
</del><ins>+        var node = this._dataTableElement.ownerDocument.elementFromPoint(x, y);
</ins><span class="cx">         var rowElement = node.enclosingNodeOrSelfWithNodeName(&quot;tr&quot;);
</span><span class="cx">         return rowElement &amp;&amp; rowElement._dataGridNode;
</span><span class="cx">     },
</span><span class="lines">@@ -970,7 +911,7 @@
</span><span class="cx">         this._sortColumnCell = cell;
</span><span class="cx"> 
</span><span class="cx">         cell.classList.add(&quot;sort-&quot; + sortOrder);
</span><del>-    
</del><ins>+
</ins><span class="cx">         this.dispatchEventToListeners(WebInspector.DataGrid.Event.SortChanged);
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="lines">@@ -1006,20 +947,19 @@
</span><span class="cx"> 
</span><span class="cx">     collapseColumnGroup: function(columnGroup)
</span><span class="cx">     {
</span><del>-        var collapserColumn = null;
-        for (var columnIdentifier in this.columns) {
-            var column = this.columns[columnIdentifier];
-            if (column.collapsesGroup == columnGroup) {
-                collapserColumn = column;
</del><ins>+        var collapserColumnIdentifier = null;
+        for (var [identifier, column] of this.columns) {
+            if (column.get(&quot;collapsesGroup&quot;) == columnGroup) {
+                collapserColumnIdentifier = identifier;
</ins><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        console.assert(collapserColumn);
-        if (!collapserColumn)
</del><ins>+        console.assert(collapserColumnIdentifier);
+        if (!collapserColumnIdentifier)
</ins><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        var cell = this._headerTableHeaders[collapserColumn.identifier];
</del><ins>+        var cell = this._headerTableCellElements.get(collapserColumnIdentifier);
</ins><span class="cx">         this._collapseColumnGroupWithCell(cell);
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="lines">@@ -1030,10 +970,9 @@
</span><span class="cx">         this.willToggleColumnGroup(cell.collapsesGroup, columnsWillCollapse);
</span><span class="cx"> 
</span><span class="cx">         var showOrHide = columnsWillCollapse ? this._hideColumn : this._showColumn;
</span><del>-        for (var columnIdentifier in this.columns) {
-            var column = this.columns[columnIdentifier];
-            if (column.group === cell.collapsesGroup)
-                showOrHide.call(this, columnIdentifier);
</del><ins>+        for (var [identifier, column] of this.columns) {
+            if (column.get(&quot;group&quot;) === cell.collapsesGroup)
+                showOrHide.call(this, identifier);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         var collapserButton = cell.querySelector(&quot;.collapser-button&quot;);
</span><span class="lines">@@ -1065,20 +1004,20 @@
</span><span class="cx"> 
</span><span class="cx">     isColumnSortColumn: function(columnIdentifier)
</span><span class="cx">     {
</span><del>-        return this._sortColumnCell === this._headerTableHeaders[columnIdentifier];
</del><ins>+        return this._sortColumnCell === this._headerTableCellElements.get(columnIdentifier);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     markColumnAsSortedBy: function(columnIdentifier, sortOrder)
</span><span class="cx">     {
</span><span class="cx">         if (this._sortColumnCell)
</span><span class="cx">             this._sortColumnCell.removeMatchingStyleClasses(&quot;sort-\\w+&quot;);
</span><del>-        this._sortColumnCell = this._headerTableHeaders[columnIdentifier];
</del><ins>+        this._sortColumnCell = this._headerTableCellElements.get(columnIdentifier);
</ins><span class="cx">         this._sortColumnCell.classList.add(&quot;sort-&quot; + sortOrder);
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     headerTableHeader: function(columnIdentifier)
</span><span class="cx">     {
</span><del>-        return this._headerTableHeaders[columnIdentifier];
</del><ins>+        return this._headerTableCellElements.get(columnIdentifier);
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     _generateSortIndicatorImagesIfNeeded: function()
</span><span class="lines">@@ -1172,8 +1111,8 @@
</span><span class="cx">     _copyTextForDataGridNode: function(node)
</span><span class="cx">     {
</span><span class="cx">         var fields = [];
</span><del>-        for (var columnIdentifier in node.dataGrid.columns)
-            fields.push(node.data[columnIdentifier] || &quot;&quot;);
</del><ins>+        for (var identifier of node.dataGrid.orderedColumns)
+            fields.push(node.data[identifier] || &quot;&quot;);
</ins><span class="cx"> 
</span><span class="cx">         var tabSeparatedValues = fields.join(&quot;\t&quot;);
</span><span class="cx">         return tabSeparatedValues;
</span><span class="lines">@@ -1247,14 +1186,14 @@
</span><span class="cx">         // column directly to the left and the column directly to the right.
</span><span class="cx">         var leftCellIndex = resizer.leftNeighboringColumnID;
</span><span class="cx">         var rightCellIndex = resizer.rightNeighboringColumnID;
</span><del>-        var firstRowCells = this.headerTableBody.rows[0].cells;
</del><ins>+        var firstRowCells = this._headerTableBodyElement.rows[0].cells;
</ins><span class="cx">         var leftEdgeOfPreviousColumn = 0;
</span><span class="cx">         for (var i = 0; i &lt; leftCellIndex; i++)
</span><span class="cx">             leftEdgeOfPreviousColumn += firstRowCells[i].offsetWidth;
</span><span class="cx"> 
</span><span class="cx">         // Differences for other resize methods
</span><span class="cx">         if (this.resizeMethod == WebInspector.DataGrid.ResizeMethod.Last) {
</span><del>-            rightCellIndex = this.resizers.length;
</del><ins>+            rightCellIndex = this.resizerElements.length;
</ins><span class="cx">         } else if (this.resizeMethod == WebInspector.DataGrid.ResizeMethod.First) {
</span><span class="cx">             leftEdgeOfPreviousColumn += firstRowCells[leftCellIndex].offsetWidth - firstRowCells[0].offsetWidth;
</span><span class="cx">             leftCellIndex = 0;
</span><span class="lines">@@ -1270,15 +1209,15 @@
</span><span class="cx"> 
</span><span class="cx">         resizer.style.left = (dragPoint - this.CenterResizerOverBorderAdjustment) + &quot;px&quot;;
</span><span class="cx"> 
</span><del>-        var percentLeftColumn = (((dragPoint - leftEdgeOfPreviousColumn) / this._dataTable.offsetWidth) * 100) + &quot;%&quot;;
-        this._headerTableColumnGroup.children[leftCellIndex].style.width = percentLeftColumn;
-        this._dataTableColumnGroup.children[leftCellIndex].style.width = percentLeftColumn;
</del><ins>+        var percentLeftColumn = (((dragPoint - leftEdgeOfPreviousColumn) / this._dataTableElement.offsetWidth) * 100) + &quot;%&quot;;
+        this._headerTableColumnGroupElement.children[leftCellIndex].style.width = percentLeftColumn;
+        this._dataTableColumnGroupElement.children[leftCellIndex].style.width = percentLeftColumn;
</ins><span class="cx"> 
</span><del>-        var percentRightColumn = (((rightEdgeOfNextColumn - dragPoint) / this._dataTable.offsetWidth) * 100) + &quot;%&quot;;
-        this._headerTableColumnGroup.children[rightCellIndex].style.width =  percentRightColumn;
-        this._dataTableColumnGroup.children[rightCellIndex].style.width = percentRightColumn;
</del><ins>+        var percentRightColumn = (((rightEdgeOfNextColumn - dragPoint) / this._dataTableElement.offsetWidth) * 100) + &quot;%&quot;;
+        this._headerTableColumnGroupElement.children[rightCellIndex].style.width =  percentRightColumn;
+        this._dataTableColumnGroupElement.children[rightCellIndex].style.width = percentRightColumn;
</ins><span class="cx"> 
</span><del>-        this._positionResizers();
</del><ins>+        this._positionResizerElements();
</ins><span class="cx">         event.preventDefault();
</span><span class="cx">         this.dispatchEventToListeners(WebInspector.DataGrid.Event.DidLayout);
</span><span class="cx">     },
</span><span class="lines">@@ -1358,10 +1297,8 @@
</span><span class="cx"> 
</span><span class="cx">     createCells: function()
</span><span class="cx">     {
</span><del>-        for (var columnIdentifier in this.dataGrid.columns) {
-            var cell = this.createCell(columnIdentifier);
-            this._element.appendChild(cell);
-        }
</del><ins>+        for (var columnIdentifier of this.dataGrid.orderedColumns)
+            this._element.appendChild(this.createCell(columnIdentifier));
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     refreshIfNeeded: function()
</span><span class="lines">@@ -1546,30 +1483,29 @@
</span><span class="cx"> 
</span><span class="cx">     createCell: function(columnIdentifier)
</span><span class="cx">     {
</span><del>-        var cell = document.createElement(&quot;td&quot;);
-        cell.className = columnIdentifier + &quot;-column&quot;;
-        cell.__columnIdentifier = columnIdentifier;
</del><ins>+        var cellElement = document.createElement(&quot;td&quot;);
+        cellElement.className = columnIdentifier + &quot;-column&quot;;
+        cellElement.__columnIdentifier = columnIdentifier;
</ins><span class="cx"> 
</span><del>-        var alignment = this.dataGrid.aligned[columnIdentifier];
-        if (alignment)
-            cell.classList.add(alignment);
</del><ins>+        var column = this.dataGrid.columns.get(columnIdentifier);
</ins><span class="cx"> 
</span><del>-        var group = this.dataGrid.groups[columnIdentifier];
-        if (group)
-            cell.classList.add(&quot;column-group-&quot; + group);
</del><ins>+        if (column.has(&quot;aligned&quot;))
+            cellElement.classList.add(column.get(&quot;aligned&quot;));
</ins><span class="cx"> 
</span><del>-        var div = document.createElement(&quot;div&quot;);
-        var content = this.createCellContent(columnIdentifier, cell);
</del><ins>+        if (column.has(&quot;group&quot;))
+            cellElement.classList.add(&quot;column-group-&quot; + column.get(&quot;group&quot;));
+
+        var div = cellElement.createChild(&quot;div&quot;);
+        var content = this.createCellContent(columnIdentifier, cellElement);
</ins><span class="cx">         div.appendChild(content instanceof Node ? content : document.createTextNode(content));
</span><del>-        cell.appendChild(div);
</del><span class="cx"> 
</span><span class="cx">         if (columnIdentifier === this.dataGrid.disclosureColumnIdentifier) {
</span><del>-            cell.classList.add(&quot;disclosure&quot;);
</del><ins>+            cellElement.classList.add(&quot;disclosure&quot;);
</ins><span class="cx">             if (this.leftPadding)
</span><del>-                cell.style.setProperty(&quot;padding-left&quot;, this.leftPadding + &quot;px&quot;);
</del><ins>+                cellElement.style.setProperty(&quot;padding-left&quot;, this.leftPadding + &quot;px&quot;);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        return cell;
</del><ins>+        return cellElement;
</ins><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     createCellContent: function(columnIdentifier)
</span><span class="lines">@@ -1579,7 +1515,7 @@
</span><span class="cx"> 
</span><span class="cx">     elementWithColumnIdentifier: function(columnIdentifier)
</span><span class="cx">     {
</span><del>-        var index = Object.keys(this.dataGrid.columns).indexOf(columnIdentifier);
</del><ins>+        var index = this.dataGrid.orderedColumns.indexOf(columnIdentifier);
</ins><span class="cx">         if (index === -1)
</span><span class="cx">             return null;
</span><span class="cx"> 
</span><span class="lines">@@ -1828,14 +1764,14 @@
</span><span class="cx">         if (previousGridNode &amp;&amp; previousGridNode.element.parentNode)
</span><span class="cx">             nextElement = previousGridNode.element.nextSibling;
</span><span class="cx">         else if (!previousGridNode)
</span><del>-            nextElement = this.dataGrid.dataTableBody.firstChild;
</del><ins>+            nextElement = this.dataGrid.dataTableBodyElement.firstChild;
</ins><span class="cx"> 
</span><span class="cx">         // If there is no next grid node, then append before the last child since the last child is the filler row.
</span><del>-        console.assert(this.dataGrid.dataTableBody.lastChild.classList.contains(&quot;filler&quot;));
</del><ins>+        console.assert(this.dataGrid.dataTableBodyElement.lastChild.classList.contains(&quot;filler&quot;));
</ins><span class="cx">         if (!nextElement)
</span><del>-            nextElement = this.dataGrid.dataTableBody.lastChild;
</del><ins>+            nextElement = this.dataGrid.dataTableBodyElement.lastChild;
</ins><span class="cx"> 
</span><del>-        this.dataGrid.dataTableBody.insertBefore(this.element, nextElement);
</del><ins>+        this.dataGrid.dataTableBodyElement.insertBefore(this.element, nextElement);
</ins><span class="cx"> 
</span><span class="cx">         if (this.expanded)
</span><span class="cx">             for (var i = 0; i &lt; this.children.length; ++i)
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceTimelineDataGridjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/TimelineDataGrid.js (163636 => 163637)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/TimelineDataGrid.js        2014-02-07 19:43:26 UTC (rev 163636)
+++ trunk/Source/WebInspectorUI/UserInterface/TimelineDataGrid.js        2014-02-07 19:49:41 UTC (rev 163637)
</span><span class="lines">@@ -49,7 +49,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (this._filterableColumns.length) {
</span><del>-        var items = [new WebInspector.FlexibleSpaceNavigationItem, this.columns[this._filterableColumns[0]].scopeBar, new WebInspector.FlexibleSpaceNavigationItem];
</del><ins>+        var items = [new WebInspector.FlexibleSpaceNavigationItem, this.columns.get(this._filterableColumns[0]).get(&quot;scopeBar&quot;), new WebInspector.FlexibleSpaceNavigationItem];
</ins><span class="cx">         this._navigationBar = new WebInspector.NavigationBar(null, items);
</span><span class="cx">         var container = this.element.appendChild(document.createElement(&quot;div&quot;));
</span><span class="cx">         container.className = &quot;navigation-bar-container&quot;;
</span><span class="lines">@@ -149,7 +149,7 @@
</span><span class="cx">         console.assert(dataGridNode);
</span><span class="cx"> 
</span><span class="cx">         for (var identifier of this._filterableColumns) {
</span><del>-            var scopeBar = this.columns[identifier].scopeBar;
</del><ins>+            var scopeBar = this.columns.get(identifier).scopeBar;
</ins><span class="cx">             if (!scopeBar || scopeBar.defaultItem.selected)
</span><span class="cx">                 continue;
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>