1/*
2 * Copyright (C) 2013 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.Section = function(title, subtitle)
27{
28    WebInspector.Object.call(this);
29
30    this.element = document.createElement("div");
31    this.element.className = "section";
32    this.element._section = this;
33
34    if (typeof title === "string" || title instanceof Node || typeof subtitle === "string") {
35        this.headerElement = document.createElement("div");
36        this.headerElement.className = "header";
37
38        this.titleElement = document.createElement("div");
39        this.titleElement.className = "title";
40
41        this.subtitleElement = document.createElement("div");
42        this.subtitleElement.className = "subtitle";
43
44        this.headerElement.appendChild(this.subtitleElement);
45        this.headerElement.appendChild(this.titleElement);
46
47        this.headerElement.addEventListener("click", this.handleClick.bind(this), false);
48        this.element.appendChild(this.headerElement);
49
50        this.title = title;
51        this.subtitle = subtitle;
52    } else
53        this.element.classList.add("no-header");
54
55    this._expanded = false;
56
57    if (!this.headerElement)
58        this.expand();
59};
60
61WebInspector.Section.Event = {
62    VisibleContentDidChange: "section-visible-content-did-change"
63};
64
65WebInspector.Section.prototype = {
66    get title()
67    {
68        return this._title;
69    },
70
71    set title(x)
72    {
73        if (this._title === x)
74            return;
75        this._title = x;
76
77        if (x instanceof Node) {
78            this.titleElement.removeChildren();
79            this.titleElement.appendChild(x);
80        } else
81          this.titleElement.textContent = x;
82    },
83
84    get subtitle()
85    {
86        return this._subtitle;
87    },
88
89    set subtitle(x)
90    {
91        if (this._subtitle === x)
92            return;
93        this._subtitle = x;
94        this.subtitleElement.textContent = x;
95    },
96
97    get subtitleAsTextForTest()
98    {
99        var result = this.subtitleElement.textContent;
100        var child = this.subtitleElement.querySelector("[data-uncopyable]");
101        if (child) {
102            var linkData = child.getAttribute("data-uncopyable");
103            if (linkData)
104                result += linkData;
105        }
106        return result;
107    },
108
109    get expanded()
110    {
111        return this._expanded;
112    },
113
114    set expanded(x)
115    {
116        if (x)
117            this.expand();
118        else
119            this.collapse();
120    },
121
122    get populated()
123    {
124        return this._populated;
125    },
126
127    set populated(x)
128    {
129        this._populated = x;
130        if (!x && this._expanded) {
131            this.onpopulate();
132            this._populated = true;
133        }
134    },
135
136    onpopulate: function()
137    {
138        // Overriden by subclasses.
139    },
140
141    get firstSibling()
142    {
143        var parent = this.element.parentElement;
144        if (!parent)
145            return null;
146
147        var childElement = parent.firstChild;
148        while (childElement) {
149            if (childElement._section)
150                return childElement._section;
151            childElement = childElement.nextSibling;
152        }
153
154        return null;
155    },
156
157    get lastSibling()
158    {
159        var parent = this.element.parentElement;
160        if (!parent)
161            return null;
162
163        var childElement = parent.lastChild;
164        while (childElement) {
165            if (childElement._section)
166                return childElement._section;
167            childElement = childElement.previousSibling;
168        }
169
170        return null;
171    },
172
173    get nextSibling()
174    {
175        var curElement = this.element;
176        do {
177            curElement = curElement.nextSibling;
178        } while (curElement && !curElement._section);
179
180        return curElement ? curElement._section : null;
181    },
182
183    get previousSibling()
184    {
185        var curElement = this.element;
186        do {
187            curElement = curElement.previousSibling;
188        } while (curElement && !curElement._section);
189
190        return curElement ? curElement._section : null;
191    },
192
193    expand: function()
194    {
195        if (this._expanded)
196            return;
197        this._expanded = true;
198        this.element.classList.add("expanded");
199
200        if (!this._populated) {
201            this.onpopulate();
202            this._populated = true;
203        } else
204            this.dispatchEventToListeners(WebInspector.Section.Event.VisibleContentDidChange);
205    },
206
207    collapse: function()
208    {
209        if (!this._expanded)
210            return;
211        this._expanded = false;
212        this.element.classList.remove("expanded");
213    },
214
215    toggleExpanded: function()
216    {
217        this.expanded = !this.expanded;
218    },
219
220    handleClick: function(e)
221    {
222        this.toggleExpanded();
223        e.stopPropagation();
224    }
225};
226
227WebInspector.Section.prototype.__proto__ = WebInspector.Object.prototype;
228