1/*
2 * Copyright (C) 2007 Apple Inc.  All rights reserved.
3 * Copyright (C) 2009 Google Inc.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1.  Redistributions of source code must retain the above copyright
10 *     notice, this list of conditions and the following disclaimer.
11 * 2.  Redistributions in binary form must reproduce the above copyright
12 *     notice, this list of conditions and the following disclaimer in the
13 *     documentation and/or other materials provided with the distribution.
14 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 *     its contributors may be used to endorse or promote products derived
16 *     from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/**
31 * @constructor
32 * @param {string|!Element} title
33 * @param {string=} subtitle
34 */
35WebInspector.Section = function(title, subtitle)
36{
37    this.element = document.createElement("div");
38    this.element.className = "section";
39    this.element._section = this;
40
41    this.headerElement = document.createElement("div");
42    this.headerElement.className = "header";
43
44    this.titleElement = document.createElement("div");
45    this.titleElement.className = "title";
46
47    this.subtitleElement = document.createElement("div");
48    this.subtitleElement.className = "subtitle";
49
50    this.headerElement.appendChild(this.subtitleElement);
51    this.headerElement.appendChild(this.titleElement);
52
53    this.headerElement.addEventListener("click", this.handleClick.bind(this), false);
54    this.element.appendChild(this.headerElement);
55
56    this.title = title;
57    this.subtitle = subtitle;
58    this._expanded = false;
59}
60
61WebInspector.Section.prototype = {
62    get title()
63    {
64        return this._title;
65    },
66
67    set title(x)
68    {
69        if (this._title === x)
70            return;
71        this._title = x;
72
73        if (x instanceof Node) {
74            this.titleElement.removeChildren();
75            this.titleElement.appendChild(x);
76        } else
77          this.titleElement.textContent = x;
78    },
79
80    get subtitle()
81    {
82        return this._subtitle;
83    },
84
85    set subtitle(x)
86    {
87        if (this._subtitle === x)
88            return;
89        this._subtitle = x;
90        this.subtitleElement.textContent = x;
91    },
92
93    get subtitleAsTextForTest()
94    {
95        var result = this.subtitleElement.textContent;
96        var child = this.subtitleElement.querySelector("[data-uncopyable]");
97        if (child) {
98            var linkData = child.getAttribute("data-uncopyable");
99            if (linkData)
100                result += linkData;
101        }
102        return result;
103    },
104
105    get expanded()
106    {
107        return this._expanded;
108    },
109
110    set expanded(x)
111    {
112        if (x)
113            this.expand();
114        else
115            this.collapse();
116    },
117
118    get populated()
119    {
120        return this._populated;
121    },
122
123    set populated(x)
124    {
125        this._populated = x;
126        if (!x && this._expanded) {
127            this.onpopulate();
128            this._populated = true;
129        }
130    },
131
132    onpopulate: function()
133    {
134        // Overriden by subclasses.
135    },
136
137    get firstSibling()
138    {
139        var parent = this.element.parentElement;
140        if (!parent)
141            return null;
142
143        var childElement = parent.firstChild;
144        while (childElement) {
145            if (childElement._section)
146                return childElement._section;
147            childElement = childElement.nextSibling;
148        }
149
150        return null;
151    },
152
153    get lastSibling()
154    {
155        var parent = this.element.parentElement;
156        if (!parent)
157            return null;
158
159        var childElement = parent.lastChild;
160        while (childElement) {
161            if (childElement._section)
162                return childElement._section;
163            childElement = childElement.previousSibling;
164        }
165
166        return null;
167    },
168
169    get nextSibling()
170    {
171        var curElement = this.element;
172        do {
173            curElement = curElement.nextSibling;
174        } while (curElement && !curElement._section);
175
176        return curElement ? curElement._section : null;
177    },
178
179    get previousSibling()
180    {
181        var curElement = this.element;
182        do {
183            curElement = curElement.previousSibling;
184        } while (curElement && !curElement._section);
185
186        return curElement ? curElement._section : null;
187    },
188
189    expand: function()
190    {
191        if (this._expanded)
192            return;
193        this._expanded = true;
194        this.element.classList.add("expanded");
195
196        if (!this._populated) {
197            this.onpopulate();
198            this._populated = true;
199        }
200    },
201
202    collapse: function()
203    {
204        if (!this._expanded)
205            return;
206        this._expanded = false;
207        this.element.classList.remove("expanded");
208    },
209
210    toggleExpanded: function()
211    {
212        this.expanded = !this.expanded;
213    },
214
215    handleClick: function(event)
216    {
217        this.toggleExpanded();
218        event.consume();
219    }
220}
221