1 /* 2 * Copyright (C) 2012 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /** 32 * @constructor 33 * @extends {WebInspector.AuditCategory} 34 * @param {string} extensionOrigin 35 * @param {string} id 36 * @param {string} displayName 37 * @param {number=} ruleCount 38 */ 39 WebInspector.ExtensionAuditCategory = function(extensionOrigin, id, displayName, ruleCount) 40 { 41 this._extensionOrigin = extensionOrigin; 42 this._id = id; 43 this._displayName = displayName; 44 this._ruleCount = ruleCount; 45 } 46 47 WebInspector.ExtensionAuditCategory.prototype = { 48 // AuditCategory interface 49 get id() 50 { 51 return this._id; 52 }, 53 54 get displayName() 55 { 56 return this._displayName; 57 }, 58 59 /** 60 * @param {!Array.<!WebInspector.NetworkRequest>} requests 61 * @param {function(!WebInspector.AuditRuleResult)} ruleResultCallback 62 * @param {function()} categoryDoneCallback 63 * @param {!WebInspector.Progress} progress 64 */ 65 run: function(requests, ruleResultCallback, categoryDoneCallback, progress) 66 { 67 var results = new WebInspector.ExtensionAuditCategoryResults(this, ruleResultCallback, categoryDoneCallback, progress); 68 WebInspector.extensionServer.startAuditRun(this, results); 69 } 70 } 71 72 /** 73 * @constructor 74 * @param {!WebInspector.ExtensionAuditCategory} category 75 * @param {function(!WebInspector.AuditRuleResult)} ruleResultCallback 76 * @param {function()} categoryDoneCallback 77 * @param {!WebInspector.Progress} progress 78 */ 79 WebInspector.ExtensionAuditCategoryResults = function(category, ruleResultCallback, categoryDoneCallback, progress) 80 { 81 this._category = category; 82 this._ruleResultCallback = ruleResultCallback; 83 this._categoryDoneCallback = categoryDoneCallback; 84 this._progress = progress; 85 this._progress.setTotalWork(1); 86 this._expectedResults = category._ruleCount; 87 this._actualResults = 0; 88 89 this.id = category.id + "-" + ++WebInspector.ExtensionAuditCategoryResults._lastId; 90 } 91 92 WebInspector.ExtensionAuditCategoryResults.prototype = { 93 done: function() 94 { 95 WebInspector.extensionServer.stopAuditRun(this); 96 this._progress.done(); 97 this._categoryDoneCallback(); 98 }, 99 100 addResult: function(displayName, description, severity, details) 101 { 102 var result = new WebInspector.AuditRuleResult(displayName); 103 result.addChild(description); 104 result.severity = severity; 105 if (details) 106 this._addNode(result, details); 107 this._addResult(result); 108 }, 109 110 _addNode: function(parent, node) 111 { 112 var contents = WebInspector.auditFormatters.partiallyApply(WebInspector.ExtensionAuditFormatters, this, node.contents); 113 var addedNode = parent.addChild(contents, node.expanded); 114 if (node.children) { 115 for (var i = 0; i < node.children.length; ++i) 116 this._addNode(addedNode, node.children[i]); 117 } 118 }, 119 120 _addResult: function(result) 121 { 122 this._ruleResultCallback(result); 123 ++this._actualResults; 124 if (typeof this._expectedResults === "number") { 125 this._progress.setWorked(this._actualResults / this._expectedResults); 126 if (this._actualResults === this._expectedResults) 127 this.done(); 128 } 129 }, 130 131 /** 132 * @param {number} progress 133 */ 134 updateProgress: function(progress) 135 { 136 this._progress.setWorked(progress); 137 }, 138 139 /** 140 * @param {string} expression 141 * @param {?Object} evaluateOptions 142 * @param {function(!WebInspector.RemoteObject)} callback 143 */ 144 evaluate: function(expression, evaluateOptions, callback) 145 { 146 /** 147 * @param {?string} error 148 * @param {!RuntimeAgent.RemoteObject} result 149 * @param {boolean=} wasThrown 150 */ 151 function onEvaluate(error, result, wasThrown) 152 { 153 if (wasThrown) 154 return; 155 var object = WebInspector.RemoteObject.fromPayload(result); 156 callback(object); 157 } 158 WebInspector.extensionServer.evaluate(expression, false, false, evaluateOptions, this._category._extensionOrigin, onEvaluate); 159 } 160 } 161 162 WebInspector.ExtensionAuditFormatters = { 163 /** 164 * @this {WebInspector.ExtensionAuditCategoryResults} 165 * @param {string} expression 166 * @param {string} title 167 * @param {?Object} evaluateOptions 168 */ 169 object: function(expression, title, evaluateOptions) 170 { 171 var parentElement = document.createElement("div"); 172 function onEvaluate(remoteObject) 173 { 174 var section = new WebInspector.ObjectPropertiesSection(remoteObject, title); 175 section.expanded = true; 176 section.editable = false; 177 parentElement.appendChild(section.element); 178 } 179 this.evaluate(expression, evaluateOptions, onEvaluate); 180 return parentElement; 181 }, 182 183 /** 184 * @this {WebInspector.ExtensionAuditCategoryResults} 185 * @param {string} expression 186 * @param {?Object} evaluateOptions 187 */ 188 node: function(expression, evaluateOptions) 189 { 190 var parentElement = document.createElement("div"); 191 /** 192 * @param {?number} nodeId 193 */ 194 function onNodeAvailable(nodeId) 195 { 196 if (!nodeId) 197 return; 198 var treeOutline = new WebInspector.ElementsTreeOutline(false, false); 199 treeOutline.rootDOMNode = WebInspector.domAgent.nodeForId(nodeId); 200 treeOutline.element.classList.add("outline-disclosure"); 201 treeOutline.setVisible(true); 202 parentElement.appendChild(treeOutline.element); 203 } 204 /** 205 * @param {!WebInspector.RemoteObject} remoteObject 206 */ 207 function onEvaluate(remoteObject) 208 { 209 remoteObject.pushNodeToFrontend(onNodeAvailable); 210 } 211 this.evaluate(expression, evaluateOptions, onEvaluate); 212 return parentElement; 213 } 214 } 215 216 WebInspector.ExtensionAuditCategoryResults._lastId = 0; 217