1/*
2 * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26WebInspector.DashboardContainerView = function() {
27    WebInspector.Object.call(this);
28
29    this._toolbarItem = new WebInspector.NavigationItem("dashboard-container", "group", WebInspector.UIString("Activity Viewer"));
30
31    // Represents currently open dashboards, with the most recent entries appended to the end.
32    this._dashboardStack = [];
33    this._currentIndex = -1;
34};
35
36WebInspector.DashboardContainerView.VisibleDashboardStyleClassName = "visible";
37
38WebInspector.DashboardContainerView.AdvanceDirection = {
39    Forward: "dashboard-container-view-advance-direction-forward",
40    Backward: "dashboard-container-view-advance-direction-backward",
41    None: "dashboard-container-view-advance-direction-none"
42};
43
44WebInspector.DashboardContainerView.ForwardIncomingDashboardStyleClassName = "slide-in-down";
45WebInspector.DashboardContainerView.BackwardIncomingDashboardStyleClassName = "slide-in-up";
46WebInspector.DashboardContainerView.ForwardOutgoingDashboardStyleClassName = "slide-out-down";
47WebInspector.DashboardContainerView.BackwardOutgoingDashboardStyleClassName = "slide-out-up";
48
49WebInspector.DashboardContainerView.prototype = {
50    constructor: WebInspector.DashboardContainerView,
51    __proto__: WebInspector.Object.prototype,
52
53    // Public
54
55    get toolbarItem()
56    {
57        return this._toolbarItem;
58    },
59
60    get currentDashboardView()
61    {
62        if (this._currentIndex === -1)
63            return null;
64
65        return this._dashboardStack[this._currentIndex];
66    },
67
68    showDashboardViewForRepresentedObject: function(representedObject)
69    {
70        var dashboardView = this._dashboardViewForRepresentedObject(representedObject);
71        if (!dashboardView)
72            return null;
73
74        if (this.currentDashboardView === dashboardView)
75            return;
76
77        var index = this._dashboardStack.indexOf(dashboardView);
78        this._showDashboardAtIndex(index);
79        return dashboardView;
80    },
81
82    hideDashboardViewForRepresentedObject: function(representedObject)
83    {
84        var onlyReturnExistingViews = true;
85        var dashboardView = this._dashboardViewForRepresentedObject(representedObject, onlyReturnExistingViews);
86
87        if (this.currentDashboardView !== dashboardView)
88            return;
89
90        console.assert(this._currentIndex > 0);
91        this._showDashboardAtIndex(this._currentIndex - 1);
92    },
93
94    closeDashboardViewForRepresentedObject: function(representedObject)
95    {
96        var onlyReturnExistingViews = true;
97        var dashboardView = this._dashboardViewForRepresentedObject(representedObject, onlyReturnExistingViews);
98        if (!dashboardView)
99            return null;
100
101        this._closeDashboardView(dashboardView);
102    },
103
104    // Private
105
106    _dashboardViewForRepresentedObject: function(representedObject, onlyReturnExistingViews)
107    {
108        console.assert(representedObject);
109
110        // Iterate over all known dashboard views and see if any are for this object.
111        for (var dashboardView of this._dashboardStack) {
112            if (dashboardView.representedObject === representedObject)
113                return dashboardView;
114        }
115
116        if (onlyReturnExistingViews)
117            return null;
118
119        try {
120            // No existing content view found, make a new one.
121            dashboardView = new WebInspector.DashboardView(representedObject);
122        } catch (e) {
123            console.error(e);
124            return null;
125        }
126
127        this._dashboardStack.push(dashboardView);
128        this._toolbarItem.element.appendChild(dashboardView.element);
129
130        return dashboardView;
131    },
132
133    _showDashboardAtIndex: function(index)
134    {
135        console.assert(index >= 0 && index <= this._dashboardStack.length - 1);
136
137        if (this._currentIndex === index)
138            return;
139
140        var advanceDirection = WebInspector.DashboardContainerView.AdvanceDirection.Forward;
141        var initialDirection = WebInspector.DashboardContainerView.AdvanceDirection.None;
142        var isFirstDashboard = this._currentIndex === -1;
143        if (!isFirstDashboard)
144            this._hideDashboardView(this.currentDashboardView, advanceDirection);
145
146        this._currentIndex = index;
147        this._showDashboardView(this.currentDashboardView, isFirstDashboard ? initialDirection : advanceDirection);
148    },
149
150    _showDashboardView: function(dashboardView, advanceDirection)
151    {
152        console.assert(dashboardView instanceof WebInspector.DashboardView);
153
154        dashboardView.shown();
155
156        var animationClass = null;
157        if (advanceDirection === WebInspector.DashboardContainerView.AdvanceDirection.Forward)
158            animationClass = WebInspector.DashboardContainerView.ForwardIncomingDashboardStyleClassName;
159        if (advanceDirection === WebInspector.DashboardContainerView.AdvanceDirection.Backward)
160            animationClass = WebInspector.DashboardContainerView.BackwardIncomingDashboardStyleClassName;
161
162        if (animationClass) {
163            function animationEnded(event) {
164                if (event.target !== dashboardView.element)
165                    return;
166
167                dashboardView.element.removeEventListener("webkitAnimationEnd", animationEnded);
168                dashboardView.element.classList.remove(animationClass);
169                dashboardView.element.classList.add(WebInspector.DashboardContainerView.VisibleDashboardStyleClassName);
170            }
171            dashboardView.element.classList.add(animationClass);
172            dashboardView.element.addEventListener("webkitAnimationEnd", animationEnded);
173        } else
174            dashboardView.element.classList.add(WebInspector.DashboardContainerView.VisibleDashboardStyleClassName);
175
176        return dashboardView;
177    },
178
179    _hideDashboardView: function(dashboardView, advanceDirection, callback)
180    {
181        console.assert(dashboardView instanceof WebInspector.DashboardView);
182        console.assert(this.currentDashboardView === dashboardView);
183
184        dashboardView.hidden();
185
186        var animationClass = null;
187        if (advanceDirection === WebInspector.DashboardContainerView.AdvanceDirection.Forward)
188            animationClass = WebInspector.DashboardContainerView.ForwardOutgoingDashboardStyleClassName;
189        if (advanceDirection === WebInspector.DashboardContainerView.AdvanceDirection.Backward)
190            animationClass = WebInspector.DashboardContainerView.BackwardOutgoingDashboardStyleClassName;
191
192        if (animationClass) {
193            function animationEnded(event) {
194                if (event.target !== dashboardView.element)
195                    return;
196
197                dashboardView.element.removeEventListener("webkitAnimationEnd", animationEnded);
198                dashboardView.element.classList.remove(animationClass);
199                dashboardView.element.classList.remove(WebInspector.DashboardContainerView.VisibleDashboardStyleClassName);
200
201                if (typeof callback === "function")
202                    callback();
203            }
204            dashboardView.element.classList.add(animationClass);
205            dashboardView.element.addEventListener("webkitAnimationEnd", animationEnded);
206        } else
207            dashboardView.element.classList.remove(WebInspector.DashboardContainerView.VisibleDashboardStyleClassName);
208    },
209
210    _closeDashboardView: function(dashboardView)
211    {
212        console.assert(dashboardView instanceof WebInspector.DashboardView);
213
214        function dissociateDashboardView() {
215            dashboardView.closed();
216            dashboardView.element.parentNode.removeChild(dashboardView.element);
217        }
218
219        var index = this._dashboardStack.indexOf(dashboardView);
220
221        if (this.currentDashboardView === dashboardView) {
222            var direction = WebInspector.DashboardContainerView.AdvanceDirection.Backward;
223            this._hideDashboardView(this.currentDashboardView, direction, dissociateDashboardView);
224            this._dashboardStack.splice(index, 1);
225            --this._currentIndex;
226            this._showDashboardView(this.currentDashboardView, direction);
227            return;
228        }
229
230        this._dashboardStack.splice(index, 1);
231        if (this._currentIndex > index)
232            --this._currentIndex;
233        dissociateDashboardView.call(this);
234    }
235};
236