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