• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.View}
33 * @param {!WebInspector.NamedFlow} flow
34 */
35WebInspector.CSSNamedFlowView = function(flow)
36{
37    WebInspector.View.call(this);
38    this.element.classList.add("css-named-flow");
39    this.element.classList.add("outline-disclosure");
40
41    this._treeOutline = new TreeOutline(this.element.createChild("ol"), true);
42
43    this._contentTreeItem = new TreeElement(WebInspector.UIString("content"), null, true);
44    this._treeOutline.appendChild(this._contentTreeItem);
45
46    this._regionsTreeItem = new TreeElement(WebInspector.UIString("region chain"), null, true);
47    this._regionsTreeItem.expand();
48    this._treeOutline.appendChild(this._regionsTreeItem);
49
50    this._flow = flow;
51
52    var content = flow.content;
53    for (var i = 0; i < content.length; ++i)
54        this._insertContentNode(content[i]);
55
56    var regions = flow.regions;
57    for (var i = 0; i < regions.length; ++i)
58        this._insertRegion(regions[i]);
59}
60
61WebInspector.CSSNamedFlowView.OversetTypeMessageMap = {
62    empty: "empty",
63    fit: "fit",
64    overset: "overset"
65}
66
67WebInspector.CSSNamedFlowView.prototype = {
68    /**
69     * @param {?WebInspector.DOMNode} rootDOMNode
70     * @return {?WebInspector.ElementsTreeOutline}
71     */
72    _createFlowTreeOutline: function(rootDOMNode)
73    {
74        if (!rootDOMNode)
75            return null;
76
77        var treeOutline = new WebInspector.ElementsTreeOutline(false, false);
78        treeOutline.element.classList.add("named-flow-element");
79        treeOutline.setVisible(true);
80        treeOutline.rootDOMNode = rootDOMNode;
81        treeOutline.wireToDomAgent();
82        WebInspector.domAgent.removeEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, treeOutline._elementsTreeUpdater._documentUpdated, treeOutline._elementsTreeUpdater);
83
84        return treeOutline;
85    },
86
87    /**
88     * @param {!DOMAgent.NodeId} contentNodeId
89     * @param {number=} index
90     */
91    _insertContentNode: function(contentNodeId, index)
92    {
93        var treeOutline = this._createFlowTreeOutline(WebInspector.domAgent.nodeForId(contentNodeId));
94        var treeItem = new TreeElement(treeOutline.element, treeOutline);
95
96        if (index === undefined) {
97            this._contentTreeItem.appendChild(treeItem);
98            return;
99        }
100
101        this._contentTreeItem.insertChild(treeItem, index);
102    },
103
104    /**
105     * @param {!CSSAgent.Region} region
106     * @param {number=} index
107     */
108    _insertRegion: function(region, index)
109    {
110        var treeOutline = this._createFlowTreeOutline(WebInspector.domAgent.nodeForId(region.nodeId));
111        treeOutline.element.classList.add("region-" + region.regionOverset);
112
113        var treeItem = new TreeElement(treeOutline.element, treeOutline);
114        var oversetText = WebInspector.UIString(WebInspector.CSSNamedFlowView.OversetTypeMessageMap[region.regionOverset]);
115        treeItem.tooltip = WebInspector.UIString("Region is %s.", oversetText);
116
117        if (index === undefined) {
118            this._regionsTreeItem.appendChild(treeItem);
119            return;
120        }
121
122        this._regionsTreeItem.insertChild(treeItem, index);
123    },
124
125    get flow()
126    {
127        return this._flow;
128    },
129
130    set flow(newFlow)
131    {
132        this._update(newFlow);
133    },
134
135    /**
136     * @param {!TreeElement} regionTreeItem
137     * @param {string} newRegionOverset
138     * @param {string} oldRegionOverset
139     */
140    _updateRegionOverset: function(regionTreeItem, newRegionOverset, oldRegionOverset)
141    {
142        var element = regionTreeItem.representedObject.element;
143        element.classList.remove("region-" + oldRegionOverset);
144        element.classList.add("region-" + newRegionOverset);
145
146        var oversetText = WebInspector.UIString(WebInspector.CSSNamedFlowView.OversetTypeMessageMap[newRegionOverset]);
147        regionTreeItem.tooltip = WebInspector.UIString("Region is %s." , oversetText);
148    },
149
150    /**
151     * @param {!Array.<!DOMAgent.NodeId>} oldContent
152     * @param {!Array.<!DOMAgent.NodeId>} newContent
153     */
154    _mergeContentNodes: function(oldContent, newContent)
155    {
156        var nodeIdSet = {};
157        for (var i = 0; i < newContent.length; ++i)
158            nodeIdSet[newContent[i]] = true;
159
160        var oldContentIndex = 0;
161        var newContentIndex = 0;
162        var contentTreeChildIndex = 0;
163
164        while (oldContentIndex < oldContent.length || newContentIndex < newContent.length) {
165            if (oldContentIndex === oldContent.length) {
166                this._insertContentNode(newContent[newContentIndex]);
167                ++newContentIndex;
168                continue;
169            }
170
171            if (newContentIndex === newContent.length) {
172                this._contentTreeItem.removeChildAtIndex(contentTreeChildIndex);
173                ++oldContentIndex;
174                continue;
175            }
176
177            if (oldContent[oldContentIndex] === newContent[newContentIndex]) {
178                ++oldContentIndex;
179                ++newContentIndex;
180                ++contentTreeChildIndex;
181                continue;
182            }
183
184            if (nodeIdSet[oldContent[oldContentIndex]]) {
185                this._insertContentNode(newContent[newContentIndex], contentTreeChildIndex);
186                ++newContentIndex;
187                ++contentTreeChildIndex;
188                continue;
189            }
190
191            this._contentTreeItem.removeChildAtIndex(contentTreeChildIndex);
192            ++oldContentIndex;
193        }
194    },
195
196    /**
197     * @param {!Array.<!CSSAgent.Region>} oldRegions
198     * @param {!Array.<!CSSAgent.Region>} newRegions
199     */
200    _mergeRegions: function(oldRegions, newRegions)
201    {
202        var nodeIdSet = {};
203        for (var i = 0; i < newRegions.length; ++i)
204            nodeIdSet[newRegions[i].nodeId] = true;
205
206        var oldRegionsIndex = 0;
207        var newRegionsIndex = 0;
208        var regionsTreeChildIndex = 0;
209
210        while (oldRegionsIndex < oldRegions.length || newRegionsIndex < newRegions.length) {
211            if (oldRegionsIndex === oldRegions.length) {
212                this._insertRegion(newRegions[newRegionsIndex]);
213                ++newRegionsIndex;
214                continue;
215            }
216
217            if (newRegionsIndex === newRegions.length) {
218                this._regionsTreeItem.removeChildAtIndex(regionsTreeChildIndex);
219                ++oldRegionsIndex;
220                continue;
221            }
222
223            if (oldRegions[oldRegionsIndex].nodeId === newRegions[newRegionsIndex].nodeId) {
224                if (oldRegions[oldRegionsIndex].regionOverset !== newRegions[newRegionsIndex].regionOverset)
225                    this._updateRegionOverset(this._regionsTreeItem.children[regionsTreeChildIndex], newRegions[newRegionsIndex].regionOverset, oldRegions[oldRegionsIndex].regionOverset);
226                ++oldRegionsIndex;
227                ++newRegionsIndex;
228                ++regionsTreeChildIndex;
229                continue;
230            }
231
232            if (nodeIdSet[oldRegions[oldRegionsIndex].nodeId]) {
233                this._insertRegion(newRegions[newRegionsIndex], regionsTreeChildIndex);
234                ++newRegionsIndex;
235                ++regionsTreeChildIndex;
236                continue;
237            }
238
239            this._regionsTreeItem.removeChildAtIndex(regionsTreeChildIndex);
240            ++oldRegionsIndex;
241        }
242    },
243
244    /**
245     * @param {!WebInspector.NamedFlow} newFlow
246     */
247    _update: function(newFlow)
248    {
249        this._mergeContentNodes(this._flow.content, newFlow.content);
250        this._mergeRegions(this._flow.regions, newFlow.regions);
251
252        this._flow = newFlow;
253    },
254
255    __proto__: WebInspector.View.prototype
256}
257