Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / CSSNamedFlowCollectionsView.js
1 /*
2  * Copyright (C) 2012 Adobe Systems Incorporated. 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  *
8  * 1. Redistributions of source code must retain the above
9  *    copyright notice, this list of conditions and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above
12  *    copyright notice, this list of conditions and the following
13  *    disclaimer in the documentation and/or other materials
14  *    provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
19  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
27  * OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 /**
31  * @constructor
32  * @extends {WebInspector.SidebarView}
33  */
34 WebInspector.CSSNamedFlowCollectionsView = function()
35 {
36     WebInspector.SidebarView.call(this, WebInspector.SidebarView.SidebarPosition.Start);
37     this.registerRequiredCSS("cssNamedFlows.css");
38
39     this._namedFlows = {};
40     this._contentNodes = {};
41     this._regionNodes = {};
42
43     this.element.classList.add("css-named-flow-collections-view");
44     this.element.classList.add("fill");
45
46     this._statusElement = document.createElement("span");
47     this._statusElement.textContent = WebInspector.UIString("CSS Named Flows");
48
49     var sidebarHeader = this.firstElement().createChild("div", "tabbed-pane-header selected sidebar-header");
50     var tab = sidebarHeader.createChild("div", "tabbed-pane-header-tab");
51     tab.createChild("span", "tabbed-pane-header-tab-title").textContent = WebInspector.UIString("CSS Named Flows");
52
53     this._sidebarContentElement = this.firstElement().createChild("div", "sidebar-content outline-disclosure");
54     this._flowListElement = this._sidebarContentElement.createChild("ol");
55     this._flowTree = new TreeOutline(this._flowListElement);
56
57     this._emptyElement = document.createElement("div");
58     this._emptyElement.classList.add("info");
59     this._emptyElement.textContent = WebInspector.UIString("No CSS Named Flows");
60
61     this._tabbedPane = new WebInspector.TabbedPane();
62     this._tabbedPane.closeableTabs = true;
63     this._tabbedPane.show(this.secondElement());
64 }
65
66 WebInspector.CSSNamedFlowCollectionsView.prototype = {
67     showInDrawer: function()
68     {
69         WebInspector.inspectorView.showCloseableViewInDrawer("css-flows", WebInspector.UIString("CSS Flows"), this);
70     },
71
72     reset: function()
73     {
74         if (!this._document)
75             return;
76
77         WebInspector.cssModel.getNamedFlowCollectionAsync(this._document.id, this._resetNamedFlows.bind(this));
78     },
79
80     /**
81      * @param {!WebInspector.DOMDocument} document
82      */
83     _setDocument: function(document)
84     {
85         this._document = document;
86         this.reset();
87     },
88
89     /**
90      * @param {!WebInspector.Event} event
91      */
92     _documentUpdated: function(event)
93     {
94         var document = /** @type {!WebInspector.DOMDocument} */ (event.data);
95         this._setDocument(document);
96     },
97
98     /**
99      * @param {boolean} hasContent
100      */
101     _setSidebarHasContent: function(hasContent)
102     {
103         if (hasContent) {
104             if (!this._emptyElement.parentNode)
105                 return;
106
107             this._sidebarContentElement.removeChild(this._emptyElement);
108             this._sidebarContentElement.appendChild(this._flowListElement);
109         } else {
110             if (!this._flowListElement.parentNode)
111                 return;
112
113             this._sidebarContentElement.removeChild(this._flowListElement);
114             this._sidebarContentElement.appendChild(this._emptyElement);
115         }
116     },
117
118     /**
119      * @param {!WebInspector.NamedFlow} flow
120      */
121     _appendNamedFlow: function(flow)
122     {
123         var flowHash = this._hashNamedFlow(flow.documentNodeId, flow.name);
124         var flowContainer = { flow: flow, flowHash: flowHash };
125
126         for (var i = 0; i < flow.content.length; ++i)
127             this._contentNodes[flow.content[i]] = flowHash;
128         for (var i = 0; i < flow.regions.length; ++i)
129             this._regionNodes[flow.regions[i].nodeId] = flowHash;
130
131         var flowTreeItem = new WebInspector.FlowTreeElement(flowContainer);
132         flowTreeItem.onselect = this._selectNamedFlowTab.bind(this, flowHash);
133
134         flowContainer.flowTreeItem = flowTreeItem;
135         this._namedFlows[flowHash] = flowContainer;
136
137         if (!this._flowTree.children.length)
138             this._setSidebarHasContent(true);
139         this._flowTree.appendChild(flowTreeItem);
140     },
141
142     /**
143      * @param {string} flowHash
144      */
145     _removeNamedFlow: function(flowHash)
146     {
147         var flowContainer = this._namedFlows[flowHash];
148
149         if (this._tabbedPane._tabsById[flowHash])
150             this._tabbedPane.closeTab(flowHash);
151         this._flowTree.removeChild(flowContainer.flowTreeItem);
152
153         var flow = flowContainer.flow;
154         for (var i = 0; i < flow.content.length; ++i)
155             delete this._contentNodes[flow.content[i]];
156         for (var i = 0; i < flow.regions.length; ++i)
157             delete this._regionNodes[flow.regions[i].nodeId];
158
159         delete this._namedFlows[flowHash];
160
161         if (!this._flowTree.children.length)
162             this._setSidebarHasContent(false);
163     },
164
165     /**
166      * @param {!WebInspector.NamedFlow} flow
167      */
168     _updateNamedFlow: function(flow)
169     {
170         var flowHash = this._hashNamedFlow(flow.documentNodeId, flow.name);
171         var flowContainer = this._namedFlows[flowHash];
172
173         if (!flowContainer)
174             return;
175
176         var oldFlow = flowContainer.flow;
177         flowContainer.flow = flow;
178
179         for (var i = 0; i < oldFlow.content.length; ++i)
180             delete this._contentNodes[oldFlow.content[i]];
181         for (var i = 0; i < oldFlow.regions.length; ++i)
182             delete this._regionNodes[oldFlow.regions[i].nodeId];
183
184         for (var i = 0; i < flow.content.length; ++i)
185             this._contentNodes[flow.content[i]] = flowHash;
186         for (var i = 0; i < flow.regions.length; ++i)
187             this._regionNodes[flow.regions[i].nodeId] = flowHash;
188
189         flowContainer.flowTreeItem.setOverset(flow.overset);
190
191         if (flowContainer.flowView)
192             flowContainer.flowView.flow = flow;
193     },
194
195     /**
196      * @param {?WebInspector.NamedFlowCollection} namedFlowCollection
197      */
198     _resetNamedFlows: function(namedFlowCollection)
199     {
200         for (var flowHash in this._namedFlows)
201             this._removeNamedFlow(flowHash);
202
203         var namedFlows = namedFlowCollection ? namedFlowCollection.namedFlowMap : {};
204         for (var flowName in namedFlows)
205             this._appendNamedFlow(namedFlows[flowName]);
206
207         if (!this._flowTree.children.length)
208             this._setSidebarHasContent(false);
209         else
210             this._showNamedFlowForNode(WebInspector.panel("elements").treeOutline.selectedDOMNode());
211     },
212
213     /**
214      * @param {!WebInspector.Event} event
215      */
216     _namedFlowCreated: function(event)
217     {
218         // FIXME: We only have support for Named Flows in the main document.
219         if (event.data.documentNodeId !== this._document.id)
220             return;
221
222         var flow = /** @type {!WebInspector.NamedFlow} */ (event.data);
223         this._appendNamedFlow(flow);
224     },
225
226     /**
227      * @param {!WebInspector.Event} event
228      */
229     _namedFlowRemoved: function(event)
230     {
231         // FIXME: We only have support for Named Flows in the main document.
232         if (event.data.documentNodeId !== this._document.id)
233             return;
234
235         this._removeNamedFlow(this._hashNamedFlow(event.data.documentNodeId, event.data.flowName));
236     },
237
238     /**
239      * @param {!WebInspector.Event} event
240      */
241     _regionLayoutUpdated: function(event)
242     {
243         // FIXME: We only have support for Named Flows in the main document.
244         if (event.data.documentNodeId !== this._document.id)
245             return;
246
247         var flow = /** @type {!WebInspector.NamedFlow} */ (event.data);
248         this._updateNamedFlow(flow);
249     },
250
251     /**
252      * @param {!WebInspector.Event} event
253      */
254     _regionOversetChanged: function(event)
255     {
256         // FIXME: We only have support for Named Flows in the main document.
257         if (event.data.documentNodeId !== this._document.id)
258             return;
259
260         var flow = /** @type {!WebInspector.NamedFlow} */ (event.data);
261         this._updateNamedFlow(flow);
262     },
263
264     /**
265      * @param {!DOMAgent.NodeId} documentNodeId
266      * @param {string} flowName
267      */
268     _hashNamedFlow: function(documentNodeId, flowName)
269     {
270         return documentNodeId + "|" + flowName;
271     },
272
273     /**
274      * @param {string} flowHash
275      */
276     _showNamedFlow: function(flowHash)
277     {
278         this._selectNamedFlowInSidebar(flowHash);
279         this._selectNamedFlowTab(flowHash);
280     },
281
282     /**
283      * @param {string} flowHash
284      */
285     _selectNamedFlowInSidebar: function(flowHash)
286     {
287         this._namedFlows[flowHash].flowTreeItem.select(true);
288     },
289
290     /**
291      * @param {string} flowHash
292      * @return {boolean}
293      */
294     _selectNamedFlowTab: function(flowHash)
295     {
296         var flowContainer = this._namedFlows[flowHash];
297
298         if (this._tabbedPane.selectedTabId === flowHash)
299             return false;
300
301         if (!this._tabbedPane.selectTab(flowHash)) {
302             if (!flowContainer.flowView)
303                 flowContainer.flowView = new WebInspector.CSSNamedFlowView(flowContainer.flow);
304
305             this._tabbedPane.appendTab(flowHash, flowContainer.flow.name, flowContainer.flowView);
306             this._tabbedPane.selectTab(flowHash);
307         }
308         return false;
309     },
310
311     /**
312      * @param {!WebInspector.Event} event
313      */
314     _selectedNodeChanged: function(event)
315     {
316         var node = /** @type {!WebInspector.DOMNode} */ (event.data);
317         this._showNamedFlowForNode(node);
318     },
319
320     /**
321      * @param {!WebInspector.Event} event
322      */
323     _tabSelected: function(event)
324     {
325         this._selectNamedFlowInSidebar(event.data.tabId);
326     },
327
328     /**
329      * @param {!WebInspector.Event} event
330      */
331     _tabClosed: function(event)
332     {
333         this._namedFlows[event.data.tabId].flowTreeItem.deselect();
334     },
335
336     /**
337      * @param {?WebInspector.DOMNode} node
338      */
339     _showNamedFlowForNode: function(node)
340     {
341         if (!node)
342             return;
343
344         if (this._regionNodes[node.id]) {
345             this._showNamedFlow(this._regionNodes[node.id]);
346             return;
347         }
348
349         while (node) {
350             if (this._contentNodes[node.id]) {
351                 this._showNamedFlow(this._contentNodes[node.id]);
352                 return;
353             }
354
355             node = node.parentNode;
356         }
357     },
358
359     wasShown: function()
360     {
361         WebInspector.SidebarView.prototype.wasShown.call(this);
362
363         WebInspector.domAgent.requestDocument(this._setDocument.bind(this));
364
365         WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._documentUpdated, this);
366
367         WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.NamedFlowCreated, this._namedFlowCreated, this);
368         WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.NamedFlowRemoved, this._namedFlowRemoved, this);
369         WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.RegionLayoutUpdated, this._regionLayoutUpdated, this);
370         WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.RegionOversetChanged, this._regionOversetChanged, this);
371
372         WebInspector.panel("elements").treeOutline.addEventListener(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, this._selectedNodeChanged, this);
373
374         this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
375         this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabClosed, this._tabClosed, this);
376     },
377
378     willHide: function()
379     {
380         WebInspector.domAgent.removeEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._documentUpdated, this);
381
382         WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.NamedFlowCreated, this._namedFlowCreated, this);
383         WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.NamedFlowRemoved, this._namedFlowRemoved, this);
384         WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.RegionLayoutUpdated, this._regionLayoutUpdated, this);
385         WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.RegionOversetChanged, this._regionOversetChanged, this);
386
387         WebInspector.panel("elements").treeOutline.removeEventListener(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, this._selectedNodeChanged, this);
388
389         this._tabbedPane.removeEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
390         this._tabbedPane.removeEventListener(WebInspector.TabbedPane.EventTypes.TabClosed, this._tabClosed, this);
391     },
392
393     __proto__: WebInspector.SidebarView.prototype
394 }
395
396 /**
397  * @constructor
398  * @extends {TreeElement}
399  */
400 WebInspector.FlowTreeElement = function(flowContainer)
401 {
402     var container = document.createElement("div");
403     container.createChild("div", "selection");
404     container.createChild("span", "title").createChild("span").textContent = flowContainer.flow.name;
405
406     TreeElement.call(this, container, flowContainer, false);
407
408     this._overset = false;
409     this.setOverset(flowContainer.flow.overset);
410 }
411
412 WebInspector.FlowTreeElement.prototype = {
413     /**
414      * @param {boolean} newOverset
415      */
416     setOverset: function(newOverset)
417     {
418         if (this._overset === newOverset)
419             return;
420
421         if (newOverset) {
422             this.title.classList.add("named-flow-overflow");
423             this.tooltip = WebInspector.UIString("Overflows.");
424         } else {
425             this.title.classList.remove("named-flow-overflow");
426             this.tooltip = "";
427         }
428
429         this._overset = newOverset;
430     },
431
432     __proto__: TreeElement.prototype
433 }