OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview Javascript that is being injected into the inspectable page | 6 * @fileoverview Javascript that is being injected into the inspectable page |
7 * while debugging. | 7 * while debugging. |
8 */ | 8 */ |
9 goog.require('goog.json'); | 9 goog.require('goog.json'); |
10 | 10 goog.provide('devtools.Injected'); |
11 /** | 11 |
12 * Returns JSON-serialized array of properties for a given node | 12 |
13 * on a given path. | 13 /** |
| 14 * Main injected object. |
| 15 * @constructor. |
| 16 */ |
| 17 devtools.Injected = function() { |
| 18 /** |
| 19 * Unique style id generator. |
| 20 * @type {number} |
| 21 * @private |
| 22 */ |
| 23 this.lastStyleId_ = 1; |
| 24 }; |
| 25 |
| 26 |
| 27 /** |
| 28 * Returns array of properties for a given node on a given path. |
14 * @param {Node} node Node to get property value for. | 29 * @param {Node} node Node to get property value for. |
15 * @param {string} args JSON-serialized {Array.<string>} Path to the | 30 * @param {Array.<string>} path Path to the nested object. |
16 * nested object, {number} Depth to the actual proto to inspect]. | 31 * @param {number} protoDepth Depth of the actual proto to inspect. |
17 * @return {string} JSON-serialized array where each property is represented | 32 * @return {Array.<Object>} Array where each property is represented |
18 * by the tree entryies [{string} type, {string} name, {Object} value]. | 33 * by the tree entries [{string} type, {string} name, {Object} value]. |
19 */ | 34 */ |
20 function devtools$$getProperties(node, args) { | 35 devtools.Injected.prototype.getProperties = function(node, path, protoDepth) { |
21 // Parse parameters. | |
22 var parsedArgs = goog.json.parse(args); | |
23 var path = parsedArgs[0]; | |
24 var protoDepth = parsedArgs[1]; | |
25 | |
26 var result = []; | 36 var result = []; |
27 var obj = node; | 37 var obj = node; |
28 | 38 |
29 // Follow the path. | 39 // Follow the path. |
30 for (var i = 0; obj && i < path.length; ++i) { | 40 for (var i = 0; obj && i < path.length; ++i) { |
31 obj = obj[path[i]]; | 41 obj = obj[path[i]]; |
32 } | 42 } |
33 | 43 |
34 if (!obj) { | 44 if (!obj) { |
35 return '[]'; | 45 return []; |
36 } | 46 } |
37 | 47 |
38 // Get to the necessary proto layer. | 48 // Get to the necessary proto layer. |
39 for (var i = 0; obj && i < protoDepth; ++i) { | 49 for (var i = 0; obj && i < protoDepth; ++i) { |
40 obj = obj.__proto__; | 50 obj = obj.__proto__; |
41 } | 51 } |
42 | 52 |
43 if (!obj) { | 53 if (!obj) { |
44 return '[]'; | 54 return []; |
45 } | 55 } |
46 | 56 |
47 // Go over properties, prepare results. | 57 // Go over properties, prepare results. |
48 for (var name in obj) { | 58 for (var name in obj) { |
49 if (protoDepth != -1 && 'hasOwnProperty' in obj && | 59 if (protoDepth != -1 && 'hasOwnProperty' in obj && |
50 !obj.hasOwnProperty(name)) { | 60 !obj.hasOwnProperty(name)) { |
51 continue; | 61 continue; |
52 } | 62 } |
53 var type = typeof obj[name]; | 63 var type = typeof obj[name]; |
54 result.push(type); | 64 result.push(type); |
55 result.push(name); | 65 result.push(name); |
56 if (type == 'string') { | 66 if (type == 'string') { |
57 var str = obj[name]; | 67 var str = obj[name]; |
58 result.push(str.length > 99 ? str.substr(0, 99) + '...' : str); | 68 result.push(str.length > 99 ? str.substr(0, 99) + '...' : str); |
59 } else if (type != 'object' && type != 'array' && | 69 } else if (type != 'object' && type != 'array' && |
60 type != 'function') { | 70 type != 'function') { |
61 result.push(obj[name]); | 71 result.push(obj[name]); |
62 } else { | 72 } else { |
63 result.push(undefined); | 73 result.push(undefined); |
64 } | 74 } |
65 } | 75 } |
66 return goog.json.serialize(result); | 76 return result; |
67 } | 77 }; |
68 | 78 |
69 | 79 |
70 /** | 80 /** |
71 * Returns JSON-serialized array of prototypes for a given node. | 81 * Returns array of prototypes for a given node. |
72 * @param {Node} node Node to get prorotypes for. | 82 * @param {Node} node Node to get prorotypes for. |
73 * @return {string} JSON-serialized array where each item is a proto name. | 83 * @return {Array<string>} Array of proto names. |
74 */ | 84 */ |
75 function devtools$$getPrototypes(node, args) { | 85 devtools.Injected.prototype.getPrototypes = function(node) { |
76 var result = []; | 86 var result = []; |
77 for (var prototype = node; prototype; prototype = prototype.__proto__) { | 87 for (var prototype = node; prototype; prototype = prototype.__proto__) { |
78 var description = Object.prototype.toString.call(prototype); | 88 var description = Object.prototype.toString.call(prototype); |
79 result.push(description.replace(/^\[object (.*)\]$/i, '$1')); | 89 result.push(description.replace(/^\[object (.*)\]$/i, '$1')); |
80 } | 90 } |
81 return goog.json.serialize(result); | 91 return result; |
82 } | 92 }; |
83 | 93 |
84 | 94 |
85 /** | 95 /** |
86 * Returns JSON-serialized style information that is used in devtools.js. | 96 * Returns style information that is used in devtools.js. |
87 * @param {Node} node Node to get prorotypes for. | 97 * @param {Node} node Node to get prorotypes for. |
88 * @param {string} args JSON-serialized boolean authorOnly that determines | 98 * @param {boolean} authorOnly Determines whether only author styles need to |
89 * whether only author styles need to be added. | 99 * be added. |
90 * @return {string} JSON-serialized style collection descriptor. | 100 * @return {string} Style collection descriptor. |
91 */ | 101 */ |
92 function devtools$$getStyles(node, args) { | 102 devtools.Injected.prototype.getStyles = function(node, authorOnly) { |
93 var authorOnly = goog.json.parse(args); | |
94 if (!node.nodeType == Node.ELEMENT_NODE) { | 103 if (!node.nodeType == Node.ELEMENT_NODE) { |
95 return '{}'; | 104 return {}; |
96 } | 105 } |
97 var matchedRules = window.getMatchedCSSRules(node, '', authorOnly); | 106 var matchedRules = window.getMatchedCSSRules(node, '', authorOnly); |
98 var matchedCSSRulesObj = []; | 107 var matchedCSSRulesObj = []; |
99 for (var i = 0; matchedRules && i < matchedRules.length; ++i) { | 108 for (var i = 0; matchedRules && i < matchedRules.length; ++i) { |
100 var rule = matchedRules[i]; | 109 var rule = matchedRules[i]; |
101 var style = devtools$$serializeStyle_(rule.style); | 110 var style = this.serializeStyle_(rule.style); |
| 111 var ruleValue = { |
| 112 'selector' : rule.selectorText, |
| 113 'style' : style |
| 114 }; |
| 115 if (rule.parentStyleSheet) { |
| 116 ruleValue['parentStyleSheet'] = { |
| 117 'href' : rule.parentStyleSheet.href, |
| 118 'ownerNodeName' : rule.parentStyleSheet.ownerNode ? |
| 119 rule.parentStyleSheet.ownerNode.name : null |
| 120 }; |
| 121 } |
102 var parentStyleSheetHref = (rule.parentStyleSheet ? | 122 var parentStyleSheetHref = (rule.parentStyleSheet ? |
103 rule.parentStyleSheet.href : undefined); | 123 rule.parentStyleSheet.href : undefined); |
104 var parentStyleSheetOwnerNodeName; | 124 var parentStyleSheetOwnerNodeName; |
105 if (rule.parentStyleSheet && rule.parentStyleSheet.ownerNode) { | 125 if (rule.parentStyleSheet && rule.parentStyleSheet.ownerNode) { |
106 parentStyleSheetOwnerNodeName = rule.parentStyleSheet.ownerNode.name; | 126 parentStyleSheetOwnerNodeName = rule.parentStyleSheet.ownerNode.name; |
107 } | 127 } |
108 matchedCSSRulesObj.push({ | 128 matchedCSSRulesObj.push(ruleValue); |
109 'selector' : rule.selectorText, | |
110 'style' : style, | |
111 'parentStyleSheetHref' : parentStyleSheetHref, | |
112 'parentStyleSheetOwnerNodeName' : parentStyleSheetOwnerNodeName | |
113 }); | |
114 } | 129 } |
115 | 130 |
116 var attributeStyles = {}; | 131 var attributeStyles = {}; |
117 var attributes = node.attributes; | 132 var attributes = node.attributes; |
118 for (var i = 0; attributes && i < attributes.length; ++i) { | 133 for (var i = 0; attributes && i < attributes.length; ++i) { |
119 if (attributes[i].style) { | 134 if (attributes[i].style) { |
120 attributeStyles[attributes[i].name] = | 135 attributeStyles[attributes[i].name] = |
121 devtools$$serializeStyle_(attributes[i].style); | 136 this.serializeStyle_(attributes[i].style); |
122 } | 137 } |
123 } | 138 } |
124 | 139 |
125 var result = { | 140 var result = { |
126 'inlineStyle' : devtools$$serializeStyle_(node.style), | 141 'inlineStyle' : this.serializeStyle_(node.style), |
127 'computedStyle' : devtools$$serializeStyle_( | 142 'computedStyle' : this.serializeStyle_( |
128 window.getComputedStyle(node, '')), | 143 window.getComputedStyle(node, '')), |
129 'matchedCSSRules' : matchedCSSRulesObj, | 144 'matchedCSSRules' : matchedCSSRulesObj, |
130 'styleAttributes' : attributeStyles | 145 'styleAttributes' : attributeStyles |
131 }; | 146 }; |
132 return goog.json.serialize(result); | 147 return result; |
133 } | 148 }; |
| 149 |
| 150 |
| 151 /** |
| 152 * Returns style decoration object for given id. |
| 153 * @param {Node} node Node to get prorotypes for. |
| 154 * @param {number} id Style id. |
| 155 * @return {Object} Style object. |
| 156 * @private |
| 157 */ |
| 158 devtools.Injected.prototype.getStyleForId_ = function(node, id) { |
| 159 var matchedRules = window.getMatchedCSSRules(node, '', false); |
| 160 for (var i = 0; matchedRules && i < matchedRules.length; ++i) { |
| 161 var rule = matchedRules[i]; |
| 162 if (rule.style.__id == id) { |
| 163 return rule.style; |
| 164 } |
| 165 } |
| 166 var attributes = node.attributes; |
| 167 for (var i = 0; attributes && i < attributes.length; ++i) { |
| 168 if (attributes[i].style && attributes[i].style.__id == id) { |
| 169 return attributes[i].style; |
| 170 } |
| 171 } |
| 172 if (node.style.__id == id) { |
| 173 return node.style; |
| 174 } |
| 175 return null; |
| 176 }; |
| 177 |
| 178 |
134 | 179 |
135 | 180 |
136 /** | 181 /** |
137 * Converts given style into serializable object. | 182 * Converts given style into serializable object. |
138 * @param {CSSStyleDeclaration} style Style to serialize. | 183 * @param {CSSStyleDeclaration} style Style to serialize. |
139 * @return {Array<Object>} Serializable object. | 184 * @return {Array<Object>} Serializable object. |
140 * @private | 185 * @private |
141 */ | 186 */ |
142 function devtools$$serializeStyle_(style) { | 187 devtools.Injected.prototype.serializeStyle_ = function(style) { |
143 var result = []; | 188 if (!style) { |
144 for (var i = 0; style && i < style.length; ++i) { | 189 return []; |
| 190 } |
| 191 if (!style.__id) { |
| 192 style.__id = this.lastStyleId_++; |
| 193 } |
| 194 var result = [ |
| 195 style.__id, |
| 196 style.__disabledProperties, |
| 197 style.__disabledPropertyValues, |
| 198 style.__disabledPropertyPriorities |
| 199 ]; |
| 200 for (var i = 0; i < style.length; ++i) { |
145 var name = style[i]; | 201 var name = style[i]; |
146 result.push([ | 202 result.push([ |
147 name, | 203 name, |
148 style.getPropertyPriority(name), | 204 style.getPropertyPriority(name), |
149 style.isPropertyImplicit(name), | 205 style.isPropertyImplicit(name), |
150 style.getPropertyShorthand(name), | 206 style.getPropertyShorthand(name), |
151 style.getPropertyValue(name) | 207 style.getPropertyValue(name) |
152 ]); | 208 ]); |
153 } | 209 } |
154 return result; | 210 return result; |
155 } | 211 }; |
| 212 |
| 213 |
| 214 /** |
| 215 * Toggles style with given id on/off. |
| 216 * @param {Node} node Node to get prorotypes for. |
| 217 * @param {number} styleId Id of style to toggle. |
| 218 * @param {boolean} enabled Determines value to toggle to, |
| 219 * @param {string} name Name of the property. |
| 220 */ |
| 221 devtools.Injected.prototype.toggleNodeStyle = function(node, styleId, enabled, |
| 222 name) { |
| 223 var style = this.getStyleForId_(node, styleId); |
| 224 if (!style) { |
| 225 return false; |
| 226 } |
| 227 |
| 228 if (!enabled) { |
| 229 if (!style.__disabledPropertyValues || |
| 230 !style.__disabledPropertyPriorities) { |
| 231 style.__disabledProperties = {}; |
| 232 style.__disabledPropertyValues = {}; |
| 233 style.__disabledPropertyPriorities = {}; |
| 234 } |
| 235 |
| 236 style.__disabledPropertyValues[name] = style.getPropertyValue(name); |
| 237 style.__disabledPropertyPriorities[name] = style.getPropertyPriority(name); |
| 238 |
| 239 if (style.getPropertyShorthand(name)) { |
| 240 var longhandProperties = this.getLonghandProperties_(style, name); |
| 241 for (var i = 0; i < longhandProperties.length; ++i) { |
| 242 style.__disabledProperties[longhandProperties[i]] = true; |
| 243 style.removeProperty(longhandProperties[i]); |
| 244 } |
| 245 } else { |
| 246 style.__disabledProperties[name] = true; |
| 247 style.removeProperty(name); |
| 248 } |
| 249 } else if (style.__disabledProperties && |
| 250 style.__disabledProperties[name]) { |
| 251 var value = style.__disabledPropertyValues[name]; |
| 252 var priority = style.__disabledPropertyPriorities[name]; |
| 253 style.setProperty(name, value, priority); |
| 254 |
| 255 delete style.__disabledProperties[name]; |
| 256 delete style.__disabledPropertyValues[name]; |
| 257 delete style.__disabledPropertyPriorities[name]; |
| 258 } |
| 259 return true; |
| 260 }; |
| 261 |
| 262 |
| 263 /** |
| 264 * Returns longhand proeprties for a given shorthand one. |
| 265 * @param {CSSStyleDeclaration} style Style declaration to use for lookup. |
| 266 * @param {string} shorthandProperty Shorthand property to get longhands for. |
| 267 * @return {Array.<string>} Array with longhand properties. |
| 268 * @private |
| 269 */ |
| 270 devtools.Injected.prototype.getLonghandProperties_ = function(style, |
| 271 shorthandProperty) { |
| 272 var properties = []; |
| 273 var foundProperties = {}; |
| 274 |
| 275 for (var i = 0; i < style.length; ++i) { |
| 276 var individualProperty = style[i]; |
| 277 if (individualProperty in foundProperties || |
| 278 style.getPropertyShorthand(individualProperty) != shorthandProperty) { |
| 279 continue; |
| 280 } |
| 281 foundProperties[individualProperty] = true; |
| 282 properties.push(individualProperty); |
| 283 } |
| 284 return properties; |
| 285 }; |
OLD | NEW |