<!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>[183322] 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/183322">183322</a></dd>
<dt>Author</dt> <dd>timothy@apple.com</dd>
<dt>Date</dt> <dd>2015-04-25 18:15:03 -0700 (Sat, 25 Apr 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: Add a WebInspector.TabBar class
https://bugs.webkit.org/show_bug.cgi?id=143442

Reviewed by Joseph Pecoraro.

* UserInterface/Main.html:
Added new files.

* UserInterface/Protocol/InspectorFrontendHostStub.js:
(window.Symbol):
(WebInspector.InspectorFrontendHostStub.prototype.showContextMenu):
Added some stubs needed to work standalone.

* UserInterface/Views/TabBar.css: Added.
(.tab-bar):
(body.window-inactive .tab-bar):
(.tab-bar &gt; .top-border):
(body.window-inactive .tab-bar &gt; .top-border):
(.tab-bar &gt; .item):
(.tab-bar &gt; :nth-child(n + 2 of .item)):
(.tab-bar &gt; .item.pinned):
(.tab-bar &gt; .item.selected):
(.tab-bar &gt; .item.new-tab-button:hover):
(.tab-bar:not(.animating) &gt; .item:not(.selected):hover + .item):
(body.window-inactive .tab-bar &gt; .item):
(body.window-inactive .tab-bar &gt; .item.selected):
(.tab-bar &gt; .item &gt; .close):
(body:not(.window-inactive) .tab-bar:not(.single-tab) &gt; .item:hover &gt; .close):
(.tab-bar.single-tab &gt; .item &gt; .close):
(.tab-bar &gt; .item &gt; .close:hover):
(.tab-bar &gt; .item &gt; .close:active):
(.tab-bar &gt; .item &gt; .flex-space):
(.tab-bar &gt; .item &gt; .flex-space:last-child):
(.tab-bar &gt; .item &gt; .icon):
(.tab-bar &gt; .item.selected &gt; .icon):
(.tab-bar &gt; .item.new-tab-button:hover &gt; .icon):
(.tab-bar &gt; .item &gt; .title):
(.tab-bar &gt; .item &gt; .title &gt; .content):
(.tab-bar:not(.animating) &gt; .item:not(.selected):hover &gt; .title):
(.tab-bar &gt; .item.selected &gt; .title):
(.tab-bar.collapsed &gt; .item):
(.tab-bar.collapsed &gt; .item &gt; .flex-space):
(.tab-bar.collapsed &gt; .item &gt; .close):
(.tab-bar.hide-titles &gt; .item &gt; .title):
(.tab-bar.hide-titles &gt; .item.selected:hover &gt; .icon):
(.tab-bar.hide-titles &gt; .item.selected:hover &gt; .close):
(.tab-bar.static-layout):
(.tab-bar.static-layout &gt; .item):
(.tab-bar.animating.closing-tab &gt; .item):
(.tab-bar.animating:matches(.expanding-tabs, .inserting-tab) &gt; .item):
(.tab-bar.animating.inserting-tab &gt; .item.being-inserted):
(.tab-bar.animating.closing-tab &gt; .item.selected):
(body.window-inactive .tab-bar.animating.closing-tab &gt; .item.selected):
(.tab-bar.dragging-tab &gt; .item.selected):

* UserInterface/Views/TabBar.js: Added.
(WebInspector.TabBar):
(WebInspector.TabBar.prototype.get newTabItem):
(WebInspector.TabBar.prototype.set newTabItem):
(WebInspector.TabBar.prototype.addTabBarItem):
(WebInspector.TabBar.prototype.insertTabBarItem.animateTabs):
(WebInspector.TabBar.prototype.insertTabBarItem.removeStyles):
(WebInspector.TabBar.prototype.insertTabBarItem):
(WebInspector.TabBar.prototype.insertTabBarItem.set else):
(WebInspector.TabBar.prototype.insertTabBarItem.set this):
(WebInspector.TabBar.animateTabs.get if):
(WebInspector.TabBar.animateTabs):
(WebInspector.TabBar.removeStyles):
(WebInspector.TabBar.prototype.insertTabBarItem):
(WebInspector.TabBar.prototype.updateLayoutSoon.update):
(WebInspector.TabBar.prototype.updateLayoutSoon):
(WebInspector.TabBar.prototype.updateLayout):
(WebInspector.TabBar.prototype.get selectedTabBarItem):
(WebInspector.TabBar.prototype.set selectedTabBarItem):
(WebInspector.TabBar.prototype.get tabBarItems):
(WebInspector.TabBar.prototype.get element):
(WebInspector.TabBar.prototype._findTabBarItem):
(WebInspector.TabBar.prototype._hasMoreThanOneNormalTab):
(WebInspector.TabBar.prototype._recordTabBarItemSizesAndPositions):
(WebInspector.TabBar.prototype._clearTabBarItemSizesAndPositions):
(WebInspector.TabBar.prototype._finishExpandingTabsAfterClose.):
(WebInspector.TabBar.prototype._finishExpandingTabsAfterClose):
(WebInspector.TabBar.prototype._handleMouseDown):
(WebInspector.TabBar.prototype._handleMouseMoved):
(WebInspector.TabBar.prototype._handleMouseUp):
(WebInspector.TabBar.prototype._handleMouseLeave):
(WebInspector.TabBar.prototype._handleNewTabMouseEnter):

* UserInterface/Views/TabBarItem.js: Added.
(WebInspector.TabBarItem):
(WebInspector.TabBarItem.prototype.get identifier):
(WebInspector.TabBarItem.prototype.get element):
(WebInspector.TabBarItem.prototype.get parentTabBar):
(WebInspector.TabBarItem.prototype.set parentTabBar):
(WebInspector.TabBarItem.prototype.get selected):
(WebInspector.TabBarItem.prototype.set selected):
(WebInspector.TabBarItem.prototype.get pinned):
(WebInspector.TabBarItem.prototype.get image):
(WebInspector.TabBarItem.prototype.set image):
(WebInspector.TabBarItem.prototype.get title):
(WebInspector.TabBarItem.prototype.set title):
(WebInspector.TabBarItem.prototype.updateLayout):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceProtocolInspectorFrontendHostStubjs">trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendHostStub.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTabBarcss">trunk/Source/WebInspectorUI/UserInterface/Views/TabBar.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTabBarjs">trunk/Source/WebInspectorUI/UserInterface/Views/TabBar.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTabBarItemjs">trunk/Source/WebInspectorUI/UserInterface/Views/TabBarItem.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (183321 => 183322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2015-04-26 01:14:13 UTC (rev 183321)
+++ trunk/Source/WebInspectorUI/ChangeLog        2015-04-26 01:15:03 UTC (rev 183322)
</span><span class="lines">@@ -1,3 +1,108 @@
</span><ins>+2015-04-06  Timothy Hatcher  &lt;timothy@apple.com&gt;
+
+        Web Inspector: Add a WebInspector.TabBar class
+        https://bugs.webkit.org/show_bug.cgi?id=143442
+
+        Reviewed by Joseph Pecoraro.
+
+        * UserInterface/Main.html:
+        Added new files.
+
+        * UserInterface/Protocol/InspectorFrontendHostStub.js:
+        (window.Symbol):
+        (WebInspector.InspectorFrontendHostStub.prototype.showContextMenu):
+        Added some stubs needed to work standalone.
+
+        * UserInterface/Views/TabBar.css: Added.
+        (.tab-bar):
+        (body.window-inactive .tab-bar):
+        (.tab-bar &gt; .top-border):
+        (body.window-inactive .tab-bar &gt; .top-border):
+        (.tab-bar &gt; .item):
+        (.tab-bar &gt; :nth-child(n + 2 of .item)):
+        (.tab-bar &gt; .item.pinned):
+        (.tab-bar &gt; .item.selected):
+        (.tab-bar &gt; .item.new-tab-button:hover):
+        (.tab-bar:not(.animating) &gt; .item:not(.selected):hover + .item):
+        (body.window-inactive .tab-bar &gt; .item):
+        (body.window-inactive .tab-bar &gt; .item.selected):
+        (.tab-bar &gt; .item &gt; .close):
+        (body:not(.window-inactive) .tab-bar:not(.single-tab) &gt; .item:hover &gt; .close):
+        (.tab-bar.single-tab &gt; .item &gt; .close):
+        (.tab-bar &gt; .item &gt; .close:hover):
+        (.tab-bar &gt; .item &gt; .close:active):
+        (.tab-bar &gt; .item &gt; .flex-space):
+        (.tab-bar &gt; .item &gt; .flex-space:last-child):
+        (.tab-bar &gt; .item &gt; .icon):
+        (.tab-bar &gt; .item.selected &gt; .icon):
+        (.tab-bar &gt; .item.new-tab-button:hover &gt; .icon):
+        (.tab-bar &gt; .item &gt; .title):
+        (.tab-bar &gt; .item &gt; .title &gt; .content):
+        (.tab-bar:not(.animating) &gt; .item:not(.selected):hover &gt; .title):
+        (.tab-bar &gt; .item.selected &gt; .title):
+        (.tab-bar.collapsed &gt; .item):
+        (.tab-bar.collapsed &gt; .item &gt; .flex-space):
+        (.tab-bar.collapsed &gt; .item &gt; .close):
+        (.tab-bar.hide-titles &gt; .item &gt; .title):
+        (.tab-bar.hide-titles &gt; .item.selected:hover &gt; .icon):
+        (.tab-bar.hide-titles &gt; .item.selected:hover &gt; .close):
+        (.tab-bar.static-layout):
+        (.tab-bar.static-layout &gt; .item):
+        (.tab-bar.animating.closing-tab &gt; .item):
+        (.tab-bar.animating:matches(.expanding-tabs, .inserting-tab) &gt; .item):
+        (.tab-bar.animating.inserting-tab &gt; .item.being-inserted):
+        (.tab-bar.animating.closing-tab &gt; .item.selected):
+        (body.window-inactive .tab-bar.animating.closing-tab &gt; .item.selected):
+        (.tab-bar.dragging-tab &gt; .item.selected):
+
+        * UserInterface/Views/TabBar.js: Added.
+        (WebInspector.TabBar):
+        (WebInspector.TabBar.prototype.get newTabItem):
+        (WebInspector.TabBar.prototype.set newTabItem):
+        (WebInspector.TabBar.prototype.addTabBarItem):
+        (WebInspector.TabBar.prototype.insertTabBarItem.animateTabs):
+        (WebInspector.TabBar.prototype.insertTabBarItem.removeStyles):
+        (WebInspector.TabBar.prototype.insertTabBarItem):
+        (WebInspector.TabBar.prototype.insertTabBarItem.set else):
+        (WebInspector.TabBar.prototype.insertTabBarItem.set this):
+        (WebInspector.TabBar.animateTabs.get if):
+        (WebInspector.TabBar.animateTabs):
+        (WebInspector.TabBar.removeStyles):
+        (WebInspector.TabBar.prototype.insertTabBarItem):
+        (WebInspector.TabBar.prototype.updateLayoutSoon.update):
+        (WebInspector.TabBar.prototype.updateLayoutSoon):
+        (WebInspector.TabBar.prototype.updateLayout):
+        (WebInspector.TabBar.prototype.get selectedTabBarItem):
+        (WebInspector.TabBar.prototype.set selectedTabBarItem):
+        (WebInspector.TabBar.prototype.get tabBarItems):
+        (WebInspector.TabBar.prototype.get element):
+        (WebInspector.TabBar.prototype._findTabBarItem):
+        (WebInspector.TabBar.prototype._hasMoreThanOneNormalTab):
+        (WebInspector.TabBar.prototype._recordTabBarItemSizesAndPositions):
+        (WebInspector.TabBar.prototype._clearTabBarItemSizesAndPositions):
+        (WebInspector.TabBar.prototype._finishExpandingTabsAfterClose.):
+        (WebInspector.TabBar.prototype._finishExpandingTabsAfterClose):
+        (WebInspector.TabBar.prototype._handleMouseDown):
+        (WebInspector.TabBar.prototype._handleMouseMoved):
+        (WebInspector.TabBar.prototype._handleMouseUp):
+        (WebInspector.TabBar.prototype._handleMouseLeave):
+        (WebInspector.TabBar.prototype._handleNewTabMouseEnter):
+
+        * UserInterface/Views/TabBarItem.js: Added.
+        (WebInspector.TabBarItem):
+        (WebInspector.TabBarItem.prototype.get identifier):
+        (WebInspector.TabBarItem.prototype.get element):
+        (WebInspector.TabBarItem.prototype.get parentTabBar):
+        (WebInspector.TabBarItem.prototype.set parentTabBar):
+        (WebInspector.TabBarItem.prototype.get selected):
+        (WebInspector.TabBarItem.prototype.set selected):
+        (WebInspector.TabBarItem.prototype.get pinned):
+        (WebInspector.TabBarItem.prototype.get image):
+        (WebInspector.TabBarItem.prototype.set image):
+        (WebInspector.TabBarItem.prototype.get title):
+        (WebInspector.TabBarItem.prototype.set title):
+        (WebInspector.TabBarItem.prototype.updateLayout):
+
</ins><span class="cx"> 2015-04-25  Timothy Hatcher  &lt;timothy@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: Make closing ContentViews more leak proof
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceProtocolInspectorFrontendHostStubjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendHostStub.js (183321 => 183322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendHostStub.js        2015-04-26 01:14:13 UTC (rev 183321)
+++ trunk/Source/WebInspectorUI/UserInterface/Protocol/InspectorFrontendHostStub.js        2015-04-26 01:15:03 UTC (rev 183322)
</span><span class="lines">@@ -30,6 +30,13 @@
</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><ins>+if (!window.Symbol) {
+    window.Symbol = function(string)
+    {
+        return string;
+    }
+}
+
</ins><span class="cx"> if (!window.InspectorFrontendHost) {
</span><span class="cx">     WebInspector.InspectorFrontendHostStub = function()
</span><span class="cx">     {
</span><span class="lines">@@ -143,6 +150,10 @@
</span><span class="cx">         {
</span><span class="cx">         },
</span><span class="cx"> 
</span><ins>+        showContextMenu: function(event, menuObject)
+        {
+        },
+
</ins><span class="cx">         // Private
</span><span class="cx"> 
</span><span class="cx">         _sendPendingMessagesToBackendIfNeeded: function()
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTabBarcss"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/TabBar.css (0 => 183322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/TabBar.css                                (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TabBar.css        2015-04-26 01:15:03 UTC (rev 183322)
</span><span class="lines">@@ -0,0 +1,305 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+.tab-bar {
+    display: flex;
+    justify-content: space-between;
+    flex-wrap: wrap;
+
+    position: relative;
+
+    border-bottom: 1px solid rgb(168, 168, 168);
+
+    background-image: linear-gradient(to bottom, rgb(199, 199, 199), rgb(184, 184, 184));
+    background-size: 100% 200%;
+
+    height: 30px;
+
+    white-space: nowrap;
+    overflow: hidden;
+
+    outline: none;
+}
+
+body.window-inactive .tab-bar {
+    border-bottom-color: rgb(219, 219, 219);
+
+    background-image: none !important;
+    background-color: rgb(236, 236, 236) !important;
+}
+
+.tab-bar &gt; .top-border {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    height: 1px;
+
+    background-color: rgb(168, 168, 168);
+
+    z-index: 0;
+}
+
+body.window-inactive .tab-bar &gt; .top-border {
+    background-color: rgb(219, 219, 219);
+}
+
+.tab-bar &gt; .item {
+    display: flex;
+    flex: 1;
+
+    position: relative;
+
+    z-index: 1;
+
+    align-items: center;
+
+    padding: 0 6px;
+
+    min-width: 30px;
+    overflow: hidden;
+
+    background-image: linear-gradient(to bottom, rgb(199, 199, 199), rgb(184, 184, 184));
+    background-size: 100% 200%;
+
+    border-top: 1px solid rgb(168, 168, 168);
+
+    height: 100%;
+    outline: none;
+
+    /* FIXME: These cause noticeable transitions when focusing the window. Fix that with JavaScript? */
+    /* transition-property: background-position, border-color; */
+    /* transition-duration: 250ms; */
+    /* transition-delay: 50ms; */
+}
+
+.tab-bar &gt; :nth-child(n + 2 of .item),
+.tab-bar.dragging-tab &gt; .item.selected {
+    border-left: 1px solid rgb(168, 168, 168);
+}
+
+.tab-bar &gt; .item.pinned {
+    width: 30px;
+    flex: none;
+    justify-content: center;
+}
+
+.tab-bar &gt; .item.selected {
+    border-top-color: rgb(190, 190, 190);
+    background-image: linear-gradient(to bottom, rgb(222, 222, 222), rgb(211, 211, 211));
+    background-size: 100% 100%;
+}
+
+.tab-bar:not(.animating) &gt; .item:not(.selected):hover,
+.tab-bar &gt; .item.new-tab-button:hover {
+    background-position: 0 100%;
+    border-top-color: rgb(152, 152, 152);
+    border-left-color: rgb(152, 152, 152);
+}
+
+.tab-bar:not(.animating) &gt; .item:not(.selected):hover + .item {
+    border-left-color: rgb(152, 152, 152);
+}
+
+body.window-inactive .tab-bar &gt; .item {
+    border-left-color: rgb(219, 219, 219) !important;
+    border-top-color: rgb(219, 219, 219) !important;
+
+    background-image: none !important;
+    background-color: rgb(236, 236, 236) !important;
+
+    transition: none;
+}
+
+body.window-inactive .tab-bar &gt; .item.selected {
+    background-image: none !important;
+    background-color: rgb(246, 246, 246) !important;
+}
+
+.tab-bar &gt; .item &gt; .close {
+    width: 16px;
+    height: 16px;
+
+    min-width: 16px;
+    min-height: 16px;
+
+    opacity: 0;
+
+    border-radius: 2px;
+
+    background-image: url(../Images/Close.svg);
+    background-repeat: no-repeat;
+
+    margin-right: 4px;
+
+    transition-property: background-color, opacity;
+    transition-duration: 250ms, 500ms;
+    transition-delay: 0, 50ms;
+}
+
+body:not(.window-inactive) .tab-bar:not(.single-tab) &gt; .item:not(.hide-close-button):hover &gt; .close {
+    opacity: 0.6;
+}
+
+.tab-bar.single-tab &gt; .item &gt; .close,
+.tab-bar &gt; .item.hide-close-button &gt; .close {
+    pointer-events: none;
+}
+
+.tab-bar &gt; .item &gt; .close:hover {
+    background-color: rgba(0, 0, 0, 0.2);
+}
+
+.tab-bar &gt; .item &gt; .close:active {
+    opacity: 0.8 !important;
+}
+
+.tab-bar &gt; .item &gt; .flex-space {
+    display: flex;
+    flex: 1;
+}
+
+.tab-bar &gt; .item &gt; .flex-space:last-child {
+    margin-right: 16px;
+}
+
+.tab-bar &gt; .item &gt; .icon {
+    width: 16px;
+    height: 16px;
+
+    min-width: 16px;
+    min-height: 16px;
+
+    opacity: 0.55; /* Assumes black glyphs. */
+
+    -webkit-user-drag: none;
+}
+
+.tab-bar &gt; .item.selected &gt; .icon {
+    opacity: 0.7;
+}
+
+.tab-bar:not(.animating) &gt; .item:not(.selected):hover &gt; .icon,
+.tab-bar &gt; .item.new-tab-button:hover &gt; .icon {
+    opacity: 0.6;
+}
+
+.tab-bar &gt; .item &gt; .title {
+    margin-left: 6px;
+
+    color: rgba(0, 0, 0, 0.55);
+
+    display: flex;
+
+    min-width: 0;
+    max-width: 400px;
+}
+
+.tab-bar &gt; .item &gt; .title &gt; .content {
+    min-width: 0;
+    width: 100%;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+}
+
+.tab-bar:not(.animating) &gt; .item:not(.selected):hover &gt; .title {
+    color: rgba(0, 0, 0, 0.6);
+}
+
+.tab-bar &gt; .item.selected &gt; .title {
+    color: rgba(0, 0, 0, 0.7);
+}
+
+.tab-bar.collapsed &gt; .item {
+    justify-content: center;
+}
+
+.tab-bar.collapsed &gt; .item &gt; .flex-space {
+    display: none;
+}
+
+.tab-bar.collapsed &gt; .item &gt; .close {
+    display: none;
+    margin-right: 0;
+}
+
+.tab-bar.hide-titles &gt; .item &gt; .title {
+    display: none;
+}
+
+.tab-bar.collapsed:not(.hide-titles) &gt; .item:not(.pinned, .hide-close-button):hover &gt; .icon,
+.tab-bar.hide-titles &gt; .item.selected:hover &gt; .icon {
+    display: none;
+}
+
+.tab-bar.collapsed:not(.hide-titles) &gt; .item:not(.hide-close-button):hover &gt; .close,
+.tab-bar.hide-titles &gt; .item.selected:hover &gt; .close {
+    display: inline-block;
+}
+
+.tab-bar.static-layout {
+    position: relative;
+}
+
+.tab-bar.static-layout &gt; .item {
+    position: absolute !important;
+    top: 0;
+}
+
+.tab-bar.animating.closing-tab &gt; .item {
+    transition-property: left;
+    transition-duration: 250ms;
+    transition-timing-function: ease-in-out;
+}
+
+.tab-bar.animating:matches(.expanding-tabs, .inserting-tab) &gt; .item {
+    transition-property: left, width;
+    transition-duration: 250ms;
+    transition-timing-function: ease-in-out;
+}
+
+.tab-bar.animating.inserting-tab &gt; .item.being-inserted {
+    z-index: 2;
+    min-width: 0 !important;
+    padding: 0 !important;
+}
+
+.tab-bar.dragging-tab &gt; .item.selected,
+.tab-bar.static-layout:not(.animating.inserting-tab):not(.dragging-tab) &gt; .item:nth-last-child(1 of :not(.pinned)),
+.tab-bar.animating.closing-tab &gt; .item.selected {
+    border-right: 1px solid rgb(168, 168, 168);
+}
+
+body.window-inactive .tab-bar.dragging-tab &gt; .item.selected,
+body.window-inactive .tab-bar.static-layout:not(.animating.inserting-tab):not(.dragging-tab) &gt; .item:nth-last-child(1 of :not(.pinned)),
+body.window-inactive .tab-bar.animating.closing-tab &gt; .item.selected {
+    border-right-color: rgb(219, 219, 219) !important;
+}
+
+.tab-bar.dragging-tab &gt; .item.selected {
+    z-index: 2;
+    pointer-events: none;
+}
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTabBarjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/TabBar.js (0 => 183322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/TabBar.js                                (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TabBar.js        2015-04-26 01:15:03 UTC (rev 183322)
</span><span class="lines">@@ -0,0 +1,672 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.TabBar = class TabBar extends WebInspector.Object
+{
+    constructor(element, tabBarItems)
+    {
+        super();
+
+        this._element = element || document.createElement(&quot;div&quot;);
+        this._element.classList.add(&quot;tab-bar&quot;);
+        this._element.tabIndex = 0;
+
+        var topBorderElement = document.createElement(&quot;div&quot;);
+        topBorderElement.classList.add(&quot;top-border&quot;);
+        this._element.appendChild(topBorderElement);
+
+        this._element.addEventListener(&quot;mousedown&quot;, this._handleMouseDown.bind(this));
+        this._element.addEventListener(&quot;mouseleave&quot;, this._handleMouseLeave.bind(this));
+
+        this._tabBarItems = [];
+
+        if (tabBarItems) {
+            for (var tabBarItem in tabBarItems)
+                this.addTabBarItem(tabBarItem);
+        }
+    }
+
+    // Public
+
+    get newTabItem()
+    {
+        return this._newTabItem || null;
+    }
+
+    set newTabItem(newTabItem)
+    {
+        if (!this._handleNewTabMouseEnterListener)
+            this._handleNewTabMouseEnterListener = this._handleNewTabMouseEnter.bind(this);
+
+        if (this._newTabItem) {
+            this._newTabItem.element.classList.remove(&quot;new-tab-button&quot;);
+            this._newTabItem.element.removeEventListener(&quot;mouseenter&quot;, this._handleNewTabMouseEnterListener);
+            this.removeTabBarItem(this._newTabItem, true);
+        }
+
+        if (newTabItem) {
+            newTabItem.element.classList.add(&quot;new-tab-button&quot;);
+            newTabItem.element.addEventListener(&quot;mouseenter&quot;, this._handleNewTabMouseEnterListener);
+            this.addTabBarItem(newTabItem, true);
+        }
+
+        this._newTabItem = newTabItem || null;
+    }
+
+    addTabBarItem(tabBarItem, doNotAnimate)
+    {
+        return this.insertTabBarItem(tabBarItem, this._tabBarItems.length, doNotAnimate);
+    }
+
+    insertTabBarItem(tabBarItem, index, doNotAnimate)
+    {
+        console.assert(tabBarItem instanceof WebInspector.TabBarItem);
+        if (!(tabBarItem instanceof WebInspector.TabBarItem))
+            return null;
+
+        if (tabBarItem.parentTabBar === this)
+            return;
+
+        if (this._tabAnimatedClosedSinceMouseEnter) {
+            // Delay adding the new tab until we can expand the tabs after a closed tab.
+            this._finishExpandingTabsAfterClose().then(function() {
+                this.insertTabBarItem(tabBarItem, index, doNotAnimate);
+            }.bind(this));
+            return;
+        }
+
+        if (tabBarItem.parentTabBar)
+            tabBarItem.parentTabBar.removeTabBarItem(tabBarItem);
+
+        tabBarItem.parentTabBar = this;
+
+        var lastIndex = this._newTabItem ? this._tabBarItems.length - 1 : this._tabBarItems.length;
+        index = Math.max(0, Math.min(index, lastIndex));
+
+        if (this._element.classList.contains(&quot;animating&quot;)) {
+            requestAnimationFrame(removeStyles.bind(this));
+            doNotAnimate = true;
+        }
+
+        var beforeTabSizesAndPositions;
+        if (!doNotAnimate)
+            beforeTabSizesAndPositions = this._recordTabBarItemSizesAndPositions();
+
+        this._tabBarItems.splice(index, 0, tabBarItem);
+
+        var nextSibling = this._tabBarItems[index + 1];
+        var nextSiblingElement = nextSibling ? nextSibling.element : (this._newTabItem ? this._newTabItem.element : null);
+
+        this._element.insertBefore(tabBarItem.element, nextSiblingElement);
+
+        this._element.classList.toggle(&quot;single-tab&quot;, !this._hasMoreThanOneNormalTab());
+
+        tabBarItem.element.style.left = null;
+        tabBarItem.element.style.width = null;
+
+        function animateTabs()
+        {
+            this._element.classList.add(&quot;animating&quot;);
+            this._element.classList.add(&quot;inserting-tab&quot;);
+
+            this._applyTabBarItemSizesAndPositions(afterTabSizesAndPositions);
+
+            this._element.addEventListener(&quot;webkitTransitionEnd&quot;, removeStylesListener);
+        }
+
+        function removeStyles()
+        {
+            this._element.classList.remove(&quot;static-layout&quot;);
+            this._element.classList.remove(&quot;animating&quot;);
+            this._element.classList.remove(&quot;inserting-tab&quot;);
+
+            tabBarItem.element.classList.remove(&quot;being-inserted&quot;);
+
+            this._clearTabBarItemSizesAndPositions();
+
+            this._element.removeEventListener(&quot;webkitTransitionEnd&quot;, removeStylesListener);
+        }
+
+        if (!doNotAnimate) {
+            var afterTabSizesAndPositions = this._recordTabBarItemSizesAndPositions();
+
+            this.updateLayout();
+
+            var previousTabBarItem = this._tabBarItems[this._tabBarItems.indexOf(tabBarItem) - 1] || null;
+            var previousTabBarItemSizeAndPosition = previousTabBarItem ? beforeTabSizesAndPositions.get(previousTabBarItem) : null;
+
+            if (previousTabBarItemSizeAndPosition)
+                beforeTabSizesAndPositions.set(tabBarItem, {left: previousTabBarItemSizeAndPosition.left + previousTabBarItemSizeAndPosition.width, width: 0});
+            else
+                beforeTabSizesAndPositions.set(tabBarItem, {left: 0, width: 0});
+
+            this._element.classList.add(&quot;static-layout&quot;);
+            tabBarItem.element.classList.add(&quot;being-inserted&quot;);
+
+            this._applyTabBarItemSizesAndPositions(beforeTabSizesAndPositions);
+
+            var removeStylesListener = removeStyles.bind(this);
+
+            requestAnimationFrame(animateTabs.bind(this));
+        } else
+            this.updateLayoutSoon();
+
+        this.dispatchEventToListeners(WebInspector.TabBar.Event.TabBarItemAdded, {tabBarItem});
+
+        return tabBarItem;
+    }
+
+    removeTabBarItem(tabBarItemOrIndex, doNotAnimate, doNotExpand)
+    {
+        var tabBarItem = this._findTabBarItem(tabBarItemOrIndex);
+        if (!tabBarItem)
+            return null;
+
+        tabBarItem.parentTabBar = null;
+
+        if (tabBarItem === this._newTabItem)
+            this.newTabItem = null;
+
+        if (this._selectedTabBarItem === tabBarItem) {
+            var index = this._tabBarItems.indexOf(tabBarItem);
+            var nextTabBarItem = this._tabBarItems[index + 1];
+            if (!nextTabBarItem || nextTabBarItem.pinned)
+                nextTabBarItem = this._tabBarItems[index - 1];
+
+            this.selectedTabBarItem = nextTabBarItem;
+        }
+
+        if (this._element.classList.contains(&quot;animating&quot;)) {
+            requestAnimationFrame(removeStyles.bind(this));
+            doNotAnimate = true;
+        }
+
+        var beforeTabSizesAndPositions;
+        if (!doNotAnimate)
+            beforeTabSizesAndPositions = this._recordTabBarItemSizesAndPositions();
+
+        var wasLastNormalTab = this._tabBarItems.indexOf(tabBarItem) === (this._newTabItem ? this._tabBarItems.length - 2 : this._tabBarItems.length - 1);
+
+        this._tabBarItems.remove(tabBarItem);
+        tabBarItem.element.remove();
+
+        var hasMoreThanOneNormalTab = this._hasMoreThanOneNormalTab();
+        this._element.classList.toggle(&quot;single-tab&quot;, !hasMoreThanOneNormalTab);
+
+        if (!hasMoreThanOneNormalTab || wasLastNormalTab || !doNotExpand) {
+            if (!doNotAnimate) {
+                this._tabAnimatedClosedSinceMouseEnter = true;
+                this._finishExpandingTabsAfterClose(beforeTabSizesAndPositions);
+            } else
+                this.updateLayoutSoon();
+
+            this.dispatchEventToListeners(WebInspector.TabBar.Event.TabBarItemRemoved, {tabBarItem});
+
+            return tabBarItem;
+        }
+
+        var lastNormalTabBarItem;
+
+        function animateTabs()
+        {
+            this._element.classList.add(&quot;animating&quot;);
+            this._element.classList.add(&quot;closing-tab&quot;);
+
+            var left = 0;
+            for (var currentTabBarItem of this._tabBarItems) {
+                var sizeAndPosition = beforeTabSizesAndPositions.get(currentTabBarItem);
+
+                if (!currentTabBarItem.pinned) {
+                    currentTabBarItem.element.style.left = left + &quot;px&quot;;
+                    left += sizeAndPosition.width;
+                    lastNormalTabBarItem = currentTabBarItem;
+                } else
+                    left = sizeAndPosition.left + sizeAndPosition.width;
+            }
+
+            // The selected tab and last tab need to draw a right border as well, so make them 1px wider.
+            if (this._selectedTabBarItem)
+                this._selectedTabBarItem.element.style.width = (parseFloat(this._selectedTabBarItem.element.style.width) + 1) + &quot;px&quot;;
+
+            if (lastNormalTabBarItem !== this._selectedTabBarItem)
+                lastNormalTabBarItem.element.style.width = (parseFloat(lastNormalTabBarItem.element.style.width) + 1) + &quot;px&quot;;
+
+            this._element.addEventListener(&quot;webkitTransitionEnd&quot;, removeStylesListener);
+        }
+
+        function removeStyles()
+        {
+            // The selected tab needs to stop drawing the right border, so make it 1px smaller. Only if it isn't the last.
+            if (this._selectedTabBarItem &amp;&amp; this._selectedTabBarItem !== lastNormalTabBarItem)
+                this._selectedTabBarItem.element.style.width = (parseFloat(this._selectedTabBarItem.element.style.width) - 1) + &quot;px&quot;;
+
+            this._element.classList.remove(&quot;animating&quot;);
+            this._element.classList.remove(&quot;closing-tab&quot;);
+
+            this.updateLayout();
+
+            this._element.removeEventListener(&quot;webkitTransitionEnd&quot;, removeStylesListener);
+        }
+
+        if (!doNotAnimate) {
+            this._element.classList.add(&quot;static-layout&quot;);
+
+            this._tabAnimatedClosedSinceMouseEnter = true;
+
+            this._applyTabBarItemSizesAndPositions(beforeTabSizesAndPositions);
+
+            var removeStylesListener = removeStyles.bind(this);
+
+            requestAnimationFrame(animateTabs.bind(this));
+        } else
+            this.updateLayoutSoon();
+
+        this.dispatchEventToListeners(WebInspector.TabBar.Event.TabBarItemRemoved, {tabBarItem});
+
+        return tabBarItem;
+    }
+
+    updateLayoutSoon()
+    {
+        if (this._updateLayoutIdentifier)
+            return;
+
+        this._needsLayout = true;
+
+        function update()
+        {
+            this._updateLayoutIdentifier = undefined;
+
+            if (this._needsLayout)
+                this.updateLayout();
+        }
+
+        this._updateLayoutIdentifier = requestAnimationFrame(update.bind(this));
+    }
+
+    updateLayout()
+    {
+        if (this._updateLayoutIdentifier) {
+            cancelAnimationFrame(this._updateLayoutIdentifier);
+            this._updateLayoutIdentifier = undefined;
+        }
+
+        if (this._element.classList.contains(&quot;static-layout&quot;))
+            return;
+
+        this._needsLayout = false;
+
+        this._element.classList.remove(&quot;hide-titles&quot;);
+        this._element.classList.remove(&quot;collapsed&quot;);
+
+        var firstNormalTabItem = null;
+        for (var tabItem of this._tabBarItems) {
+            if (tabItem.pinned)
+                continue;
+            firstNormalTabItem = tabItem;
+            break;
+        }
+
+        if (!firstNormalTabItem)
+            return;
+
+        if (firstNormalTabItem.element.offsetWidth &gt;= 120)
+            return;
+
+        this._element.classList.add(&quot;collapsed&quot;);
+
+        if (firstNormalTabItem.element.offsetWidth &gt;= 60)
+            return;
+
+        this._element.classList.add(&quot;hide-titles&quot;);
+    }
+
+    get selectedTabBarItem()
+    {
+        return this._selectedTabBarItem;
+    }
+
+    set selectedTabBarItem(tabBarItemOrIndex)
+    {
+        var tabBarItem = this._findTabBarItem(tabBarItemOrIndex);
+
+        if (this._selectedTabBarItem === tabBarItem)
+            return;
+
+        if (this._selectedTabBarItem)
+            this._selectedTabBarItem.selected = false;
+
+        this._selectedTabBarItem = tabBarItem || null;
+
+        if (this._selectedTabBarItem)
+            this._selectedTabBarItem.selected = true;
+
+        this.dispatchEventToListeners(WebInspector.TabBar.Event.TabBarItemSelected);
+    }
+
+    get tabBarItems()
+    {
+        return this._tabBarItems;
+    }
+
+    get element()
+    {
+        return this._element;
+    }
+
+    // Private
+
+    _findTabBarItem(tabBarItemOrIndex)
+    {
+        if (typeof tabBarItemOrIndex === &quot;number&quot;)
+            return this._tabBarItems[tabBarItemOrIndex] || null;
+
+        if (tabBarItemOrIndex instanceof WebInspector.TabBarItem) {
+            if (this._tabBarItems.includes(tabBarItemOrIndex))
+                return tabBarItemOrIndex;
+        }
+
+        return null;
+    }
+
+    _hasMoreThanOneNormalTab()
+    {
+        var normalTabCount = 0;
+        for (var tabBarItem of this._tabBarItems) {
+            if (tabBarItem.pinned)
+                continue;
+            ++normalTabCount;
+            if (normalTabCount &gt;= 2)
+                return true;
+        }
+
+        return false;
+    }
+
+    _recordTabBarItemSizesAndPositions()
+    {
+        var tabBarItemSizesAndPositions = new Map;
+
+        var barRect = this._element.getBoundingClientRect();
+
+        for (var tabBarItem of this._tabBarItems) {
+            var boundingRect = tabBarItem.element.getBoundingClientRect();
+            tabBarItemSizesAndPositions.set(tabBarItem, {left: boundingRect.left - barRect.left, width: boundingRect.width});
+        }
+
+        return tabBarItemSizesAndPositions;
+    }
+
+    _applyTabBarItemSizesAndPositions(tabBarItemSizesAndPositions, skipTabBarItem)
+    {
+        for (var [tabBarItem, sizeAndPosition] of tabBarItemSizesAndPositions) {
+            if (skipTabBarItem &amp;&amp; tabBarItem === skipTabBarItem)
+                continue;
+            tabBarItem.element.style.left = sizeAndPosition.left + &quot;px&quot;;
+            tabBarItem.element.style.width = sizeAndPosition.width + &quot;px&quot;;
+        }
+    }
+
+    _clearTabBarItemSizesAndPositions(skipTabBarItem)
+    {
+        for (var tabBarItem of this._tabBarItems) {
+            if (skipTabBarItem &amp;&amp; tabBarItem === skipTabBarItem)
+                continue;
+            tabBarItem.element.style.left = null;
+            tabBarItem.element.style.width = null;
+        }
+    }
+
+    _finishExpandingTabsAfterClose(beforeTabSizesAndPositions)
+    {
+        return new Promise(function(resolve, reject) {
+            console.assert(this._tabAnimatedClosedSinceMouseEnter);
+            this._tabAnimatedClosedSinceMouseEnter = false;
+
+            if (!beforeTabSizesAndPositions)
+                beforeTabSizesAndPositions = this._recordTabBarItemSizesAndPositions();
+
+            this._element.classList.remove(&quot;static-layout&quot;);
+            this._clearTabBarItemSizesAndPositions();
+
+            var afterTabSizesAndPositions = this._recordTabBarItemSizesAndPositions();
+
+            this._applyTabBarItemSizesAndPositions(beforeTabSizesAndPositions);
+
+            function animateTabs()
+            {
+                this._element.classList.add(&quot;static-layout&quot;);
+                this._element.classList.add(&quot;animating&quot;);
+                this._element.classList.add(&quot;expanding-tabs&quot;);
+
+                this._applyTabBarItemSizesAndPositions(afterTabSizesAndPositions);
+
+                this._element.addEventListener(&quot;webkitTransitionEnd&quot;, removeStylesListener);
+            }
+
+            function removeStyles()
+            {
+                this._element.classList.remove(&quot;static-layout&quot;);
+                this._element.classList.remove(&quot;animating&quot;);
+                this._element.classList.remove(&quot;expanding-tabs&quot;);
+
+                this._clearTabBarItemSizesAndPositions();
+
+                this.updateLayout();
+
+                this._element.removeEventListener(&quot;webkitTransitionEnd&quot;, removeStylesListener);
+
+                resolve();
+            }
+
+            var removeStylesListener = removeStyles.bind(this);
+
+            requestAnimationFrame(animateTabs.bind(this));
+        }.bind(this));
+    }
+
+    _handleMouseDown(event)
+    {
+        // Only handle left mouse clicks.
+        if (event.button !== 0 || event.ctrlKey)
+            return;
+
+        var itemElement = event.target.enclosingNodeOrSelfWithClass(WebInspector.TabBarItem.StyleClassName);
+        if (!itemElement)
+            return;
+
+        var tabBarItem = itemElement[WebInspector.TabBarItem.ElementReferenceSymbol];
+        if (!tabBarItem || tabBarItem === this._newTabItem)
+            return;
+
+        var closeButtonElement = event.target.enclosingNodeOrSelfWithClass(WebInspector.TabBarItem.CloseButtonStyleClassName);
+        if (closeButtonElement) {
+            this.removeTabBarItem(tabBarItem, false, true);
+            return;
+        }
+
+        this.selectedTabBarItem = tabBarItem;
+
+        if (tabBarItem.pinned || !this._hasMoreThanOneNormalTab())
+            return;
+
+        this._firstNormalTabItemIndex = 0;
+        for (var i = 0; i &lt; this._tabBarItems.length; ++i) {
+            if (this._tabBarItems[i].pinned)
+                continue;
+            this._firstNormalTabItemIndex = i;
+            break;
+        }
+
+        this._mouseIsDown = true;
+
+        this._mouseMovedEventListener = this._handleMouseMoved.bind(this);
+        this._mouseUpEventListener = this._handleMouseUp.bind(this);
+
+        // Register these listeners on the document so we can track the mouse if it leaves the tab bar.
+        document.addEventListener(&quot;mousemove&quot;, this._mouseMovedEventListener, true);
+        document.addEventListener(&quot;mouseup&quot;, this._mouseUpEventListener, true);
+
+        event.preventDefault();
+        event.stopPropagation();
+    }
+
+    _handleMouseMoved(event)
+    {
+        console.assert(event.button === 0);
+        console.assert(this._mouseIsDown);
+        if (!this._mouseIsDown)
+            return;
+
+        console.assert(this._selectedTabBarItem);
+        if (!this._selectedTabBarItem)
+            return;
+
+        event.preventDefault();
+        event.stopPropagation();
+
+        if (!this._element.classList.contains(&quot;static-layout&quot;)) {
+            this._applyTabBarItemSizesAndPositions(this._recordTabBarItemSizesAndPositions());
+            this._element.classList.add(&quot;static-layout&quot;);
+            this._element.classList.add(&quot;dragging-tab&quot;);
+        }
+
+        if (this._mouseOffset === undefined)
+            this._mouseOffset = event.pageX - this._selectedTabBarItem.element.totalOffsetLeft;
+
+        var tabBarMouseOffset = event.pageX - this.element.totalOffsetLeft;
+        var newLeft = tabBarMouseOffset - this._mouseOffset;
+
+        this._selectedTabBarItem.element.style.left = newLeft + &quot;px&quot;;
+
+        var selectedTabMidX = newLeft + (this._selectedTabBarItem.element.getBoundingClientRect().width / 2);
+
+        var currentIndex = this._tabBarItems.indexOf(this._selectedTabBarItem);
+        var newIndex = currentIndex;
+
+        for (var tabBarItem of this._tabBarItems) {
+            if (tabBarItem === this._selectedTabBarItem)
+                continue;
+
+            var tabBarItemRect = tabBarItem.element.getBoundingClientRect();
+
+            if (selectedTabMidX &lt; tabBarItemRect.left || selectedTabMidX &gt; tabBarItemRect.right)
+                continue;
+
+            newIndex = this._tabBarItems.indexOf(tabBarItem);
+            break;
+        }
+
+        newIndex = Math.max(this._firstNormalTabItemIndex, newIndex);
+        newIndex = Math.min(this._newTabItem ? this._tabBarItems.length - 2 : this._tabBarItems.length - 1, newIndex);
+
+        if (currentIndex === newIndex)
+            return;
+
+        this._tabBarItems.splice(currentIndex, 1);
+        this._tabBarItems.splice(newIndex, 0, this._selectedTabBarItem);
+
+        var nextSibling = this._tabBarItems[newIndex + 1];
+        var nextSiblingElement = nextSibling ? nextSibling.element : (this._newTabItem ? this._newTabItem.element : null);
+
+        this._element.insertBefore(this._selectedTabBarItem.element, nextSiblingElement);
+
+        // FIXME: Animate the tabs that move to make room for the selected tab. This was causing me trouble when I tried.
+
+        var left = 0;
+        for (var tabBarItem of this._tabBarItems) {
+            if (tabBarItem !== this._selectedTabBarItem &amp;&amp; tabBarItem !== this._newTabItem &amp;&amp; parseFloat(tabBarItem.element.style.left) !== left)
+                tabBarItem.element.style.left = left + &quot;px&quot;;
+            left += parseFloat(tabBarItem.element.style.width);
+        }
+    }
+
+    _handleMouseUp(event)
+    {
+        console.assert(event.button === 0);
+        console.assert(this._mouseIsDown);
+        if (!this._mouseIsDown)
+            return;
+
+        this._element.classList.remove(&quot;dragging-tab&quot;);
+
+        if (!this._tabAnimatedClosedSinceMouseEnter) {
+            this._element.classList.remove(&quot;static-layout&quot;)
+            this._clearTabBarItemSizesAndPositions();
+        } else {
+            var left = 0;
+            for (var tabBarItem of this._tabBarItems) {
+                if (tabBarItem === this._selectedTabBarItem)
+                    tabBarItem.element.style.left = left + &quot;px&quot;;
+                left += parseFloat(tabBarItem.element.style.width);
+            }
+        }
+
+        this._mouseIsDown = false;
+        this._mouseOffset = undefined;
+
+        document.removeEventListener(&quot;mousemove&quot;, this._mouseMovedEventListener, true);
+        document.removeEventListener(&quot;mouseup&quot;, this._mouseUpEventListener, true);
+
+        this._mouseMovedEventListener = null;
+        this._mouseUpEventListener = null;
+
+        event.preventDefault();
+        event.stopPropagation();
+
+        this.dispatchEventToListeners(WebInspector.TabBar.Event.TabBarItemsReordered);
+    }
+
+    _handleMouseLeave(event)
+    {
+        if (this._mouseIsDown || !this._tabAnimatedClosedSinceMouseEnter || !this._element.classList.contains(&quot;static-layout&quot;) || this._element.classList.contains(&quot;animating&quot;))
+            return;
+
+        // This event can still fire when the mouse is inside the element if DOM nodes are added, removed or generally change inside.
+        // Check if the mouse really did leave the element by checking the bounds.
+        // FIXME: Is this a WebKit bug or correct behavior?
+        var barRect = this._element.getBoundingClientRect();
+        var newTabItemRect = this._newTabItem ? this._newTabItem.element.getBoundingClientRect() : null;
+        if (event.pageY &gt; barRect.top &amp;&amp; event.pageY &lt; barRect.bottom &amp;&amp; event.pageX &gt; barRect.left &amp;&amp; event.pageX &lt; (newTabItemRect ? newTabItemRect.right : barRect.right))
+            return;
+
+        this._finishExpandingTabsAfterClose();
+    }
+
+    _handleNewTabMouseEnter(event)
+    {
+        if (!this._tabAnimatedClosedSinceMouseEnter || !this._element.classList.contains(&quot;static-layout&quot;) || this._element.classList.contains(&quot;animating&quot;))
+            return;
+
+        this._finishExpandingTabsAfterClose();
+    }
+};
+
+WebInspector.TabBar.Event = {
+    TabBarItemSelected: &quot;tab-bar-tab-bar-item-selected&quot;,
+    TabBarItemAdded: &quot;tab-bar-tab-bar-item-added&quot;,
+    TabBarItemRemoved: &quot;tab-bar-tab-bar-item-removed&quot;,
+    TabBarItemsReordered: &quot;tab-bar-tab-bar-items-reordered&quot;
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTabBarItemjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/TabBarItem.js (0 => 183322)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/TabBarItem.js                                (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TabBarItem.js        2015-04-26 01:15:03 UTC (rev 183322)
</span><span class="lines">@@ -0,0 +1,160 @@
</span><ins>+/*
+ * Copyright (C) 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.TabBarItem = class TabBarItem extends WebInspector.Object
+{
+    constructor(image, title, pinned, representedObject)
+    {
+        super();
+
+        this._parentTabBar = null;
+
+        this._element = document.createElement(&quot;div&quot;);
+        this._element.classList.add(WebInspector.TabBarItem.StyleClassName);
+        if (pinned)
+            this._element.classList.add(&quot;pinned&quot;);
+        this._element[WebInspector.TabBarItem.ElementReferenceSymbol] = this;
+
+        if (!pinned) {
+            this._closeButtonElement = document.createElement(&quot;div&quot;);
+            this._closeButtonElement.classList.add(WebInspector.TabBarItem.CloseButtonStyleClassName);
+            this._closeButtonElement.title = WebInspector.UIString(&quot;Click to close this tab&quot;);
+            this._element.appendChild(this._closeButtonElement);
+
+            var flexSpaceElement = document.createElement(&quot;div&quot;);
+            flexSpaceElement.classList.add(&quot;flex-space&quot;);
+            this._element.appendChild(flexSpaceElement);
+        }
+
+        this._iconElement = document.createElement(&quot;img&quot;);
+        this._iconElement.classList.add(&quot;icon&quot;);
+        this._element.appendChild(this._iconElement);
+
+        if (!pinned) {
+            var flexSpaceElement = document.createElement(&quot;div&quot;);
+            flexSpaceElement.classList.add(&quot;flex-space&quot;);
+            this._element.appendChild(flexSpaceElement);
+        }
+
+        this.title = title;
+        this.image = image;
+        this.representedObject = representedObject;
+    }
+
+    // Public
+
+    get element()
+    {
+        return this._element;
+    }
+
+    get representedObject()
+    {
+        return this._representedObject;
+    }
+
+    set representedObject(representedObject)
+    {
+        this._representedObject = representedObject || null;
+    }
+
+    get parentTabBar()
+    {
+        return this._parentTabBar;
+    }
+
+    set parentTabBar(tabBar)
+    {
+        this._parentTabBar = tabBar || null;
+    }
+
+    get selected()
+    {
+        return this._element.classList.contains(&quot;selected&quot;);
+    }
+
+    set selected(selected)
+    {
+        this._element.classList.toggle(&quot;selected&quot;, selected);
+    }
+
+    get hideCloseButton()
+    {
+        return this._element.classList.contains(&quot;hide-close-button&quot;);
+    }
+
+    set hideCloseButton(hide)
+    {
+        this._element.classList.toggle(&quot;hide-close-button&quot;, hide);
+    }
+
+    get pinned()
+    {
+        return this._element.classList.contains(&quot;pinned&quot;);
+    }
+
+    get image()
+    {
+        return this._iconElement.src;
+    }
+
+    set image(url)
+    {
+        this._iconElement.src = url || &quot;&quot;;
+    }
+
+    get title()
+    {
+        return this._element.title || &quot;&quot;;
+    }
+
+    set title(title)
+    {
+        if (title &amp;&amp; !this.pinned) {
+            this._titleElement = document.createElement(&quot;span&quot;);
+            this._titleElement.classList.add(&quot;title&quot;);
+
+            this._titleContentElement = document.createElement(&quot;span&quot;);
+            this._titleContentElement.classList.add(&quot;content&quot;);
+            this._titleElement.appendChild(this._titleContentElement);
+
+            this._titleContentElement.textContent = title;
+
+            this._element.insertBefore(this._titleElement, this._element.lastChild);
+        } else {
+            if (this._titleElement)
+                this._titleElement.remove();
+
+            this._titleContentElement = null;
+            this._titleElement = null;
+        }
+
+        this._element.title = title || &quot;&quot;;
+    }
+};
+
+WebInspector.TabBarItem.StyleClassName = &quot;item&quot;;
+WebInspector.TabBarItem.CloseButtonStyleClassName = &quot;close&quot;;
+WebInspector.TabBarItem.ElementReferenceSymbol = Symbol(&quot;tab-bar-item&quot;);
</ins></span></pre>
</div>
</div>

</body>
</html>