1/* 2 * Copyright (C) 2007 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 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29WebInspector.MetricsSidebarPane = function() 30{ 31 WebInspector.SidebarPane.call(this, WebInspector.UIString("Metrics")); 32 this._inlineStyleId = null; 33 this._inlineStyleInjectedScriptId = null; 34} 35 36WebInspector.MetricsSidebarPane.prototype = { 37 update: function(node) 38 { 39 if (node) 40 this.node = node; 41 else 42 node = this.node; 43 44 if (!node || !node.ownerDocument.defaultView || node.nodeType !== Node.ELEMENT_NODE) { 45 this.bodyElement.removeChildren(); 46 return; 47 } 48 49 var self = this; 50 var callback = function(stylePayload) { 51 if (!stylePayload) 52 return; 53 var style = WebInspector.CSSStyleDeclaration.parseStyle(stylePayload); 54 self._update(style); 55 }; 56 InjectedScriptAccess.get(node.injectedScriptId).getComputedStyle(node.id, callback); 57 58 var inlineStyleCallback = function(stylePayload) { 59 if (!stylePayload) 60 return; 61 self._inlineStyleId = stylePayload.id; 62 self._inlineStyleInjectedScriptId = stylePayload.injectedScriptId; 63 }; 64 InjectedScriptAccess.get(node.injectedScriptId).getInlineStyle(node.id, inlineStyleCallback); 65 }, 66 67 _update: function(style) 68 { 69 var metricsElement = document.createElement("div"); 70 metricsElement.className = "metrics"; 71 72 function createBoxPartElement(style, name, side, suffix) 73 { 74 var propertyName = (name !== "position" ? name + "-" : "") + side + suffix; 75 var value = style.getPropertyValue(propertyName); 76 if (value === "" || (name !== "position" && value === "0px")) 77 value = "\u2012"; 78 else if (name === "position" && value === "auto") 79 value = "\u2012"; 80 value = value.replace(/px$/, ""); 81 82 var element = document.createElement("div"); 83 element.className = side; 84 element.textContent = value; 85 element.addEventListener("dblclick", this.startEditing.bind(this, element, name, propertyName), false); 86 return element; 87 } 88 89 // Display types for which margin is ignored. 90 var noMarginDisplayType = { 91 "table-cell": true, 92 "table-column": true, 93 "table-column-group": true, 94 "table-footer-group": true, 95 "table-header-group": true, 96 "table-row": true, 97 "table-row-group": true 98 }; 99 100 // Display types for which padding is ignored. 101 var noPaddingDisplayType = { 102 "table-column": true, 103 "table-column-group": true, 104 "table-footer-group": true, 105 "table-header-group": true, 106 "table-row": true, 107 "table-row-group": true 108 }; 109 110 // Position types for which top, left, bottom and right are ignored. 111 var noPositionType = { 112 "static": true 113 }; 114 115 var boxes = ["content", "padding", "border", "margin", "position"]; 116 var boxLabels = [WebInspector.UIString("content"), WebInspector.UIString("padding"), WebInspector.UIString("border"), WebInspector.UIString("margin"), WebInspector.UIString("position")]; 117 var previousBox; 118 for (var i = 0; i < boxes.length; ++i) { 119 var name = boxes[i]; 120 121 if (name === "margin" && noMarginDisplayType[style.display]) 122 continue; 123 if (name === "padding" && noPaddingDisplayType[style.display]) 124 continue; 125 if (name === "position" && noPositionType[style.position]) 126 continue; 127 128 var boxElement = document.createElement("div"); 129 boxElement.className = name; 130 131 if (name === "content") { 132 var width = style.width.replace(/px$/, ""); 133 var widthElement = document.createElement("span"); 134 widthElement.textContent = width; 135 widthElement.addEventListener("dblclick", this.startEditing.bind(this, widthElement, "width", "width"), false); 136 137 var height = style.height.replace(/px$/, ""); 138 var heightElement = document.createElement("span"); 139 heightElement.textContent = height; 140 heightElement.addEventListener("dblclick", this.startEditing.bind(this, heightElement, "height", "height"), false); 141 142 boxElement.appendChild(widthElement); 143 boxElement.appendChild(document.createTextNode(" \u00D7 ")); 144 boxElement.appendChild(heightElement); 145 } else { 146 var suffix = (name === "border" ? "-width" : ""); 147 148 var labelElement = document.createElement("div"); 149 labelElement.className = "label"; 150 labelElement.textContent = boxLabels[i]; 151 boxElement.appendChild(labelElement); 152 153 boxElement.appendChild(createBoxPartElement.call(this, style, name, "top", suffix)); 154 boxElement.appendChild(document.createElement("br")); 155 boxElement.appendChild(createBoxPartElement.call(this, style, name, "left", suffix)); 156 157 if (previousBox) 158 boxElement.appendChild(previousBox); 159 160 boxElement.appendChild(createBoxPartElement.call(this, style, name, "right", suffix)); 161 boxElement.appendChild(document.createElement("br")); 162 boxElement.appendChild(createBoxPartElement.call(this, style, name, "bottom", suffix)); 163 } 164 165 previousBox = boxElement; 166 } 167 168 metricsElement.appendChild(previousBox); 169 this.bodyElement.removeChildren(); 170 this.bodyElement.appendChild(metricsElement); 171 }, 172 173 startEditing: function(targetElement, box, styleProperty) 174 { 175 if (WebInspector.isBeingEdited(targetElement)) 176 return; 177 178 var context = { box: box, styleProperty: styleProperty }; 179 180 WebInspector.startEditing(targetElement, this.editingCommitted.bind(this), this.editingCancelled.bind(this), context); 181 }, 182 183 editingCancelled: function(element, context) 184 { 185 this.update(); 186 }, 187 188 editingCommitted: function(element, userInput, previousContent, context) 189 { 190 if (userInput === previousContent) 191 return this.editingCancelled(element, context); // nothing changed, so cancel 192 193 if (context.box !== "position" && (!userInput || userInput === "\u2012")) 194 userInput = "0px"; 195 else if (context.box === "position" && (!userInput || userInput === "\u2012")) 196 userInput = "auto"; 197 198 // Append a "px" unit if the user input was just a number. 199 if (/^\d+$/.test(userInput)) 200 userInput += "px"; 201 202 var self = this; 203 var callback = function(success) { 204 if (!success) 205 return; 206 self.dispatchEventToListeners("metrics edited"); 207 self.update(); 208 }; 209 InjectedScriptAccess.get(this._inlineStyleInjectedScriptId).setStyleProperty(this._inlineStyleId, context.styleProperty, userInput, callback); 210 } 211} 212 213WebInspector.MetricsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; 214