Reviewed by Pavel Feldman.
Web Inspector: add audits support to extension API
Exposed (late) adding of categories from AuditPanel.
Removed indexOfObjectInListSortedByFunction in favor of
insertionIndexForObjectInListSortedByFunction (the former had
weird interface always returning negative numbers and was only used in
the latter).
https://bugs.webkit.org/show_bug.cgi?id=44518
Tests: inspector/extensions-audits-api.html
* WebCore.gypi:
* WebCore.vcproj/WebCore.vcproj:
* inspector/front-end/AuditFormatters.js: Added.
(WebInspector.applyFormatters):
(WebInspector.AuditFormatters.text):
(WebInspector.AuditFormatters.snippet):
(WebInspector.AuditFormatters.concat):
(WebInspector.AuditFormatters.url):
* inspector/front-end/AuditLauncherView.js:
(WebInspector.AuditLauncherView):
(WebInspector.AuditLauncherView.prototype.addCategory.compareCategories):
(WebInspector.AuditLauncherView.prototype.addCategory):
(WebInspector.AuditLauncherView.prototype._launchButtonClicked):
(WebInspector.AuditLauncherView.prototype._selectAllClicked):
(WebInspector.AuditLauncherView.prototype._categoryClicked):
(WebInspector.AuditLauncherView.prototype._createCategoryElement):
(WebInspector.AuditLauncherView.prototype._createLauncherUI):
* inspector/front-end/AuditResultView.js:
(WebInspector.AuditCategoryResultPane.prototype._appendResult):
* inspector/front-end/AuditsPanel.js:
(WebInspector.AuditsPanel):
(WebInspector.AuditsPanel.prototype.addCategory):
(WebInspector.AuditsPanel.prototype.getCategory):
(WebInspector.AuditsPanel.prototype._executeAudit):
(WebInspector.AuditCategory.prototype.run):
* inspector/front-end/ExtensionAPI.js:
(WebInspector.injectedExtensionAPI):
(WebInspector.injectedExtensionAPI.EventSinkImpl.prototype.addListener):
(WebInspector.injectedExtensionAPI.EventSinkImpl.prototype._fire):
(WebInspector.injectedExtensionAPI.EventSinkImpl.prototype._dispatch):
(WebInspector.injectedExtensionAPI.EventSink):
(WebInspector.injectedExtensionAPI.InspectorExtensionAPI):
(WebInspector.injectedExtensionAPI.Panels.prototype.create):
(WebInspector.injectedExtensionAPI.Audits):
(WebInspector.injectedExtensionAPI.Audits.prototype.addCategory):
(WebInspector.injectedExtensionAPI.AuditCategory.customDispatch):
(WebInspector.injectedExtensionAPI.AuditCategory):
(WebInspector.injectedExtensionAPI.AuditCategoryImpl):
(WebInspector.injectedExtensionAPI.AuditResult):
(WebInspector.injectedExtensionAPI.AuditResult.prototype.get Severity):
(WebInspector.injectedExtensionAPI.AuditResultImpl):
(WebInspector.injectedExtensionAPI.AuditResultImpl.prototype.addResult):
(WebInspector.injectedExtensionAPI.AuditResultImpl.prototype.createResult):
(WebInspector.injectedExtensionAPI.AuditResultImpl.prototype.done):
(WebInspector.injectedExtensionAPI.AuditResultImpl.prototype._nodeFactory):
(WebInspector.injectedExtensionAPI.AuditResultNode):
(WebInspector.injectedExtensionAPI.AuditResultNode.prototype.addChild):
* inspector/front-end/ExtensionAuditCategory.js: Added.
(WebInspector.ExtensionAuditCategory):
(WebInspector.ExtensionAuditCategory.prototype.get id):
(WebInspector.ExtensionAuditCategory.prototype.get displayName):
(WebInspector.ExtensionAuditCategory.prototype.get ruleCount):
(WebInspector.ExtensionAuditCategory.prototype.run):
(WebInspector.ExtensionAuditCategoryResults):
(WebInspector.ExtensionAuditCategoryResults.prototype.get complete):
(WebInspector.ExtensionAuditCategoryResults.prototype.cancel):
(WebInspector.ExtensionAuditCategoryResults.prototype.addResult):
(WebInspector.ExtensionAuditCategoryResults.prototype._addNode):
(WebInspector.ExtensionAuditCategoryResults.prototype._addResult):
* inspector/front-end/ExtensionCommon.js: Added.
(WebInspector.commonExtensionSymbols):
* inspector/front-end/ExtensionServer.js:
(WebInspector.ExtensionServer):
(WebInspector.ExtensionServer.prototype.startAuditRun):
(WebInspector.ExtensionServer.prototype.stopAuditRun):
(WebInspector.ExtensionServer.prototype._postNotification):
(WebInspector.ExtensionServer.prototype._onAddAuditCategory):
(WebInspector.ExtensionServer.prototype._onAddAuditResult):
(WebInspector.ExtensionServer.prototype._onStopAuditCategoryRun):
(WebInspector.ExtensionServer.prototype._addExtensions):
(WebInspector.ExtensionServer.prototype._buildExtensionAPIInjectedScript):
(WebInspector.ExtensionStatus):
* inspector/front-end/WebKit.qrc:
* inspector/front-end/inspector.html:
* inspector/front-end/utilities.js:
():
2010-08-26 Andrey Kosyakov <caseq@chromium.org>
Reviewed by Pavel Feldman.
Web Inspector: add audits support to extension API
https://bugs.webkit.org/show_bug.cgi?id=44518
* inspector/audits-panel-functional.html:
* inspector/audits-tests.js: Added.
(frontend_collectAuditResults):
(frontend_collectTextContent):
* inspector/extensions-api-expected.txt:
* inspector/extensions-audits-api-expected.txt: Added.
* inspector/extensions-audits-api.html: Added.
* inspector/extensions-audits-expected.txt: Added.
* inspector/extensions-audits-tests.js: Added.
(extension_runAudits.onMessage):
(extension_runAudits):
(frontend_runExtensionAudits.onAuditsDone):
* inspector/extensions-audits.html: Added.
* inspector/extensions-expected.txt:
* inspector/resources/audits-script3.js: Removed.
* platform/chromium/test_expectations.txt:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@66218
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2010-08-26 Andrey Kosyakov <caseq@chromium.org>
+
+ Reviewed by Pavel Feldman.
+
+ Web Inspector: add audits support to extension API
+ https://bugs.webkit.org/show_bug.cgi?id=44518
+
+ * inspector/audits-panel-functional.html:
+ * inspector/audits-tests.js: Added.
+ (frontend_collectAuditResults):
+ (frontend_collectTextContent):
+ * inspector/extensions-api-expected.txt:
+ * inspector/extensions-audits-api-expected.txt: Added.
+ * inspector/extensions-audits-api.html: Added.
+ * inspector/extensions-audits-expected.txt: Added.
+ * inspector/extensions-audits-tests.js: Added.
+ (extension_runAudits.onMessage):
+ (extension_runAudits):
+ (frontend_runExtensionAudits.onAuditsDone):
+ * inspector/extensions-audits.html: Added.
+ * inspector/extensions-expected.txt:
+ * inspector/resources/audits-script3.js: Removed.
+ * platform/chromium/test_expectations.txt:
+
2010-08-25 Jeremy Orlow <jorlow@chromium.org>
Reviewed by Steve Block.
}
</style>
<script src="../http/tests/inspector/inspector-test.js"></script>
+<script src="audits-tests.js"></script>
<!-- These scripts are needed to result in a violation of the max JS resource count from the same domain -->
<script src="resources/audits-script1.js"></script>
<link rel="stylesheet" href="resources/audits-style1.css" type="text/css">
<script src="resources/audits-script2.js"></script>
-<script src="resources/audits-script3.js"></script>
<script>
function doit()
testController.runAfterPendingDispatches(function() {
// Audits are done, check results.
- WebInspector.panels.audits.showResults(WebInspector.panels.audits.auditResultsTreeElement.children[0].results);
- var liElements = WebInspector.panels.audits.visibleView.element.getElementsByTagName("li");
- for (var j = 0; j < liElements.length; ++j) {
- if (liElements[j].treeElement)
- liElements[j].treeElement.expand();
- }
- var output = [];
- frontend_collectTextContent(WebInspector.panels.audits.visibleView.element, 0, output);
+ var output = frontend_collectAuditResults();
// Avoid influencing tests that require resource tracking to be disabled.
InspectorBackend.disableResourceTracking(false);
testController.runAfterPendingDispatches(function() {
}
}
-function frontend_collectTextContent(element, level, output)
-{
- var nodeOutput = "";
- var child = element.firstChild;
- while (child) {
- if (child.nodeType === Node.TEXT_NODE) {
- for (var i = 0; i < level; ++i)
- nodeOutput += " ";
- nodeOutput += child.nodeValue;
- } else if (child.nodeType === Node.ELEMENT_NODE) {
- if (nodeOutput !== "") {
- output.push(nodeOutput);
- nodeOutput = "";
- }
- frontend_collectTextContent(child, level + 1, output);
- }
- child = child.nextSibling;
- }
- if (nodeOutput !== "")
- output.push(nodeOutput);
- return;
-}
-
</script>
</head>
--- /dev/null
+function frontend_collectAuditResults()
+{
+ WebInspector.panels.audits.showResults(WebInspector.panels.audits.auditResultsTreeElement.children[0].results);
+ var liElements = WebInspector.panels.audits.visibleView.element.getElementsByTagName("li");
+ for (var j = 0; j < liElements.length; ++j) {
+ if (liElements[j].treeElement)
+ liElements[j].treeElement.expand();
+ }
+ var output = [];
+ frontend_collectTextContent(WebInspector.panels.audits.visibleView.element, 0, output);
+ return output;
+}
+
+function frontend_collectTextContent(element, level, output)
+{
+ var nodeOutput = "";
+ var child = element.firstChild;
+
+ while (child) {
+ if (child.nodeType === Node.TEXT_NODE) {
+ for (var i = 0; i < level; ++i)
+ nodeOutput += " ";
+ nodeOutput += child.nodeValue;
+ } else if (child.nodeType === Node.ELEMENT_NODE) {
+ if (nodeOutput !== "") {
+ output.push(nodeOutput);
+ nodeOutput = "";
+ }
+ frontend_collectTextContent(child, level + 1, output);
+ }
+ child = child.nextSibling;
+ }
+ if (nodeOutput !== "")
+ output.push(nodeOutput);
+}
Running tests...
RUNNING TEST: extension_testAPI
{
+ audits : {
+ addCategory : <function>
+ }
inspectedWindow : {
onLoaded : {
addListener : <function>
--- /dev/null
+Tests audits support in WebInspector Extensions API
+
+Started extension.
+Running tests...
+RUNNING TEST: extension_testAuditsAPI
+Added audit category, result dump follows:
+{
+ onAuditStarted : {
+ addListener : <function>
+ removeListener : <function>
+ }
+}
+category.onAuditStarted fired, results dump follows:
+{
+ addResult : <function>
+ createResult : <function>
+ done : <function>
+ url : <function>
+ snippet : <function>
+ text : <function>
+ Severity : {
+ Info : "info"
+ Warning : "warning"
+ Severe : "severe"
+ }
+}
+{
+ contents : {
+ 0 : "Subtree"
+ }
+ children : {
+ }
+ expanded : false
+ addChild : <function>
+}
+Audits complete:
+ Extension audits
+All tests done.
+
--- /dev/null
+<html>
+<head>
+<script src="../http/tests/inspector/inspector-test.js"></script>
+<script src="extensions-test.js"></script>
+<script src="audits-tests.js"></script>
+<script src="extensions-audits-tests.js"></script>
+
+<script type="text/javascript">
+
+function extension_testAuditsAPI(nextTest)
+{
+ function onStartAuditCategory(results)
+ {
+ log("category.onAuditStarted fired, results dump follows:");
+ dumpObject(results);
+ var node = results.createResult("Subtree");
+ dumpObject(node);
+ results.done();
+ }
+ var category = webInspector.audits.addCategory("Extension audits", 20);
+ category.onAuditStarted.addListener(onStartAuditCategory);
+ log("Added audit category, result dump follows:");
+ dumpObject(category);
+ extension_runAudits(nextTest);
+}
+
+function runAudits()
+{
+ evaluateInWebInspector("frontend_runAudits");
+}
+
+</script>
+</head>
+<body onload="onload()">
+<p>Tests audits support in WebInspector Extensions API</p>
+</body>
+</html>
--- /dev/null
+Tests audits support in WebInspector Extensions API
+
+Started extension.
+Running tests...
+RUNNING TEST: extension_testAudits
+Added audit category.
+category.onAuditStarted fired
+failedCategory.onAuditStarted fired, throwing exception
+Audits complete:
+ Extension audits
+ Failed rule (42)
+ this rule always fails
+ Rule with details subtree (1)
+ This rule has a lot of details
+ Subtree
+ Some url:
+ WebKit
+ more text
+ http://www.google.com
+ ... and a snippet
+ function rand()
+ {
+ return 4;
+ }
+ Passed rule
+ this rule always passes ok
+ Extension audits that fail
+All tests done.
+
--- /dev/null
+function extension_runAudits(callback)\r
+{\r
+ function onMessage(event)\r
+ {\r
+ if (event.data === "audit-tests-done")\r
+ callback();\r
+ }\r
+ top.addEventListener("message", onMessage, false);\r
+ webInspector.inspectedWindow.evaluate("evaluateInWebInspector('frontend_runExtensionAudits')");\r
+}\r
+\r
+function frontend_runExtensionAudits(testController)\r
+{\r
+ const launcherView = WebInspector.panels.audits._launcherView;\r
+ launcherView._selectAllClicked(false);\r
+ launcherView._auditPresentStateElement.checked = true;\r
+\r
+ var extensionCategories = document.evaluate("label[starts-with(.,'Extension ')]/input[@type='checkbox']",\r
+ WebInspector.panels.audits._launcherView._categoriesElement, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);\r
+\r
+ for (var i = 0; i < extensionCategories.snapshotLength; ++i)\r
+ extensionCategories.snapshotItem(i).click();\r
+\r
+ function onAuditsDone()\r
+ {\r
+ var output = frontend_collectAuditResults();\r
+ InjectedScriptAccess.getDefault().evaluate("log(unescape('" + escape("Audits complete:\n" + output.join("\n")) + "'));", function() {\r
+ top.postMessage("audit-tests-done", "*");\r
+ });\r
+ }\r
+\r
+ frontend_addSniffer(WebInspector.panels.audits, "_auditFinishedCallback", onAuditsDone, true);\r
+ launcherView._launchButtonClicked();\r
+}\r
--- /dev/null
+<html>
+<head>
+<script src="../http/tests/inspector/inspector-test.js"></script>
+<script src="extensions-test.js"></script>
+<script src="audits-tests.js"></script>
+<script src="extensions-audits-tests.js"></script>
+
+<script type="text/javascript">
+
+function extension_testAudits(nextTest)
+{
+ function onStartAuditCategory(results)
+ {
+ log("category.onAuditStarted fired");
+ results.addResult("Passed rule", "this rule always passes ok", results.Severity.Info);
+ results.addResult("Failed rule (42)", "this rule always fails", results.Severity.Severe);
+
+ var node = results.createResult("Subtree");
+ node.addChild("Some url: ", results.url("http://www.webkit.org", "WebKit"), " more text ", results.url("http://www.google.com"));
+ var nestedNode = node.addChild("... and a snippet");
+ nestedNode.expanded = true;
+ nestedNode.addChild(results.snippet("function rand()\n{\n return 4;\n}"));
+
+ results.addResult("Rule with details subtree (1)", "This rule has a lot of details", results.Severity.Warning, node);
+ // Audit normally terminates when number of added rule results is equal to
+ // the rule count declared when adding a category. done() is only for
+ // emergency cases, when we know we won't be able to run the rest of the rules.
+ results.done();
+ }
+ function onStartAuditFailedCategory()
+ {
+ log("failedCategory.onAuditStarted fired, throwing exception");
+ throw "oops!";
+ }
+ function onStartAuditDisabledCategory(results)
+ {
+ log("FAIL: failedCategory.onAuditStarted fired");
+ results.done();
+ }
+
+ var category = webInspector.audits.addCategory("Extension audits", 20);
+ category.onAuditStarted.addListener(onStartAuditCategory);
+ log("Added audit category.");
+
+ var failedCategory = webInspector.audits.addCategory("Extension audits that fail", 2);
+ failedCategory.onAuditStarted.addListener(onStartAuditFailedCategory);
+
+ var disabledCategory = webInspector.audits.addCategory("Disabled extension audits", 2);
+ disabledCategory.onAuditStarted.addListener(onStartAuditDisabledCategory);
+
+ extension_runAudits(nextTest);
+}
+
+</script>
+</head>
+<body onload="onload()">
+<p>Tests audits support in WebInspector Extensions API</p>
+</body>
+</html>
resource: .../LayoutTests/inspector/extensions-test.js
resource: .../LayoutTests/inspector/extensions.html
RUNNING TEST: extension_testGetInvalidResource
-Attempted to retrieve invalid resource: {"code":"E_NOTFOUND","description":"Object not found (%s)","details":[2128506],"isError":true}
+Attempted to retrieve invalid resource: {"code":"E_NOTFOUND","description":"Object not found: %s","details":[2128506],"isError":true}
RUNNING TEST: extension_testResourceNotification
Resource finished: .../inspector/resources/extension-main.html
All tests done.
+++ /dev/null
-function foo3()
-{
-}
WONTFIX SKIP : http/tests/security/MessagePort/event-listener-context.html = FAIL
WONTFIX SKIP : inspector/extensions.html = FAIL
WONTFIX SKIP : inspector/extensions-api.html = FAIL
+WONTFIX SKIP : inspector/extensions-audits.html = FAIL
+WONTFIX SKIP : inspector/extensions-audits-api.html = FAIL
// Implement java testing harness.
BUG36681 DEFER SKIP : java = TEXT
+2010-08-26 Andrey Kosyakov <caseq@chromium.org>
+
+ Reviewed by Pavel Feldman.
+
+ Web Inspector: add audits support to extension API
+ Exposed (late) adding of categories from AuditPanel.
+ Removed indexOfObjectInListSortedByFunction in favor of
+ insertionIndexForObjectInListSortedByFunction (the former had
+ weird interface always returning negative numbers and was only used in
+ the latter).
+ https://bugs.webkit.org/show_bug.cgi?id=44518
+
+ Tests: inspector/extensions-audits-api.html
+
+ * WebCore.gypi:
+ * WebCore.vcproj/WebCore.vcproj:
+ * inspector/front-end/AuditFormatters.js: Added.
+ (WebInspector.applyFormatters):
+ (WebInspector.AuditFormatters.text):
+ (WebInspector.AuditFormatters.snippet):
+ (WebInspector.AuditFormatters.concat):
+ (WebInspector.AuditFormatters.url):
+ * inspector/front-end/AuditLauncherView.js:
+ (WebInspector.AuditLauncherView):
+ (WebInspector.AuditLauncherView.prototype.addCategory.compareCategories):
+ (WebInspector.AuditLauncherView.prototype.addCategory):
+ (WebInspector.AuditLauncherView.prototype._launchButtonClicked):
+ (WebInspector.AuditLauncherView.prototype._selectAllClicked):
+ (WebInspector.AuditLauncherView.prototype._categoryClicked):
+ (WebInspector.AuditLauncherView.prototype._createCategoryElement):
+ (WebInspector.AuditLauncherView.prototype._createLauncherUI):
+ * inspector/front-end/AuditResultView.js:
+ (WebInspector.AuditCategoryResultPane.prototype._appendResult):
+ * inspector/front-end/AuditsPanel.js:
+ (WebInspector.AuditsPanel):
+ (WebInspector.AuditsPanel.prototype.addCategory):
+ (WebInspector.AuditsPanel.prototype.getCategory):
+ (WebInspector.AuditsPanel.prototype._executeAudit):
+ (WebInspector.AuditCategory.prototype.run):
+ * inspector/front-end/ExtensionAPI.js:
+ (WebInspector.injectedExtensionAPI):
+ (WebInspector.injectedExtensionAPI.EventSinkImpl.prototype.addListener):
+ (WebInspector.injectedExtensionAPI.EventSinkImpl.prototype._fire):
+ (WebInspector.injectedExtensionAPI.EventSinkImpl.prototype._dispatch):
+ (WebInspector.injectedExtensionAPI.EventSink):
+ (WebInspector.injectedExtensionAPI.InspectorExtensionAPI):
+ (WebInspector.injectedExtensionAPI.Panels.prototype.create):
+ (WebInspector.injectedExtensionAPI.Audits):
+ (WebInspector.injectedExtensionAPI.Audits.prototype.addCategory):
+ (WebInspector.injectedExtensionAPI.AuditCategory.customDispatch):
+ (WebInspector.injectedExtensionAPI.AuditCategory):
+ (WebInspector.injectedExtensionAPI.AuditCategoryImpl):
+ (WebInspector.injectedExtensionAPI.AuditResult):
+ (WebInspector.injectedExtensionAPI.AuditResult.prototype.get Severity):
+ (WebInspector.injectedExtensionAPI.AuditResultImpl):
+ (WebInspector.injectedExtensionAPI.AuditResultImpl.prototype.addResult):
+ (WebInspector.injectedExtensionAPI.AuditResultImpl.prototype.createResult):
+ (WebInspector.injectedExtensionAPI.AuditResultImpl.prototype.done):
+ (WebInspector.injectedExtensionAPI.AuditResultImpl.prototype._nodeFactory):
+ (WebInspector.injectedExtensionAPI.AuditResultNode):
+ (WebInspector.injectedExtensionAPI.AuditResultNode.prototype.addChild):
+ * inspector/front-end/ExtensionAuditCategory.js: Added.
+ (WebInspector.ExtensionAuditCategory):
+ (WebInspector.ExtensionAuditCategory.prototype.get id):
+ (WebInspector.ExtensionAuditCategory.prototype.get displayName):
+ (WebInspector.ExtensionAuditCategory.prototype.get ruleCount):
+ (WebInspector.ExtensionAuditCategory.prototype.run):
+ (WebInspector.ExtensionAuditCategoryResults):
+ (WebInspector.ExtensionAuditCategoryResults.prototype.get complete):
+ (WebInspector.ExtensionAuditCategoryResults.prototype.cancel):
+ (WebInspector.ExtensionAuditCategoryResults.prototype.addResult):
+ (WebInspector.ExtensionAuditCategoryResults.prototype._addNode):
+ (WebInspector.ExtensionAuditCategoryResults.prototype._addResult):
+ * inspector/front-end/ExtensionCommon.js: Added.
+ (WebInspector.commonExtensionSymbols):
+ * inspector/front-end/ExtensionServer.js:
+ (WebInspector.ExtensionServer):
+ (WebInspector.ExtensionServer.prototype.startAuditRun):
+ (WebInspector.ExtensionServer.prototype.stopAuditRun):
+ (WebInspector.ExtensionServer.prototype._postNotification):
+ (WebInspector.ExtensionServer.prototype._onAddAuditCategory):
+ (WebInspector.ExtensionServer.prototype._onAddAuditResult):
+ (WebInspector.ExtensionServer.prototype._onStopAuditCategoryRun):
+ (WebInspector.ExtensionServer.prototype._addExtensions):
+ (WebInspector.ExtensionServer.prototype._buildExtensionAPIInjectedScript):
+ (WebInspector.ExtensionStatus):
+ * inspector/front-end/WebKit.qrc:
+ * inspector/front-end/inspector.html:
+ * inspector/front-end/utilities.js:
+ ():
+
2010-08-25 Jeremy Orlow <jorlow@chromium.org>
Reviewed by Steve Block.
'inspector/front-end/AbstractTimelinePanel.js',
'inspector/front-end/ApplicationCacheItemsView.js',
'inspector/front-end/AuditCategories.js',
+ 'inspector/front-end/AuditFormatters.js',
'inspector/front-end/AuditLauncherView.js',
'inspector/front-end/AuditResultView.js',
'inspector/front-end/AuditRules.js',
'inspector/front-end/ElementsTreeOutline.js',
'inspector/front-end/EventListenersSidebarPane.js',
'inspector/front-end/ExtensionAPI.js',
+ 'inspector/front-end/ExtensionAuditCategory.js',
+ 'inspector/front-end/ExtensionCommon.js',
'inspector/front-end/ExtensionPanel.js',
'inspector/front-end/ExtensionRegistryStub.js',
'inspector/front-end/ExtensionServer.js',
>\r
</File>\r
<File\r
+ RelativePath="..\inspector\front-end\AuditFormatters.js"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath="..\inspector\front-end\AuditLauncherView.js"\r
>\r
</File>\r
>\r
</File>\r
<File\r
+ RelativePath="..\inspector\front-end\ExtensionAuditCategory.js"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\inspector\front-end\ExtensionCommon.js"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath="..\inspector\front-end\ExtensionPanel.js"\r
>\r
</File>\r
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-WebInspector.AuditLauncherView = function(categoriesById, runnerCallback)
+WebInspector.AuditLauncherView = function(runnerCallback)
{
WebInspector.View.call(this);
- this._categoriesById = categoriesById;
this._runnerCallback = runnerCallback;
this._categoryIdPrefix = "audit-category-item-";
this._auditRunning = false;
this._contentElement = document.createElement("div");
this._contentElement.className = "audit-launcher-view-content";
this.element.appendChild(this._contentElement);
+ this._boundCategoryClickListener = this._categoryClicked.bind(this);
this._resetResourceCount();
- function categorySortFunction(a, b)
- {
- var aTitle = a.displayName || "";
- var bTitle = b.displayName || "";
- return aTitle.localeCompare(bTitle);
- }
- var sortedCategories = [];
- for (var id in this._categoriesById)
- sortedCategories.push(this._categoriesById[id]);
- sortedCategories.sort(categorySortFunction);
+ this._sortedCategories = [];
- if (!sortedCategories.length) {
- this._headerElement = document.createElement("h1");
- this._headerElement.className = "no-audits";
- this._headerElement.textContent = WebInspector.UIString("No audits to run");
- this._contentElement.appendChild(this._headerElement);
- } else
- this._createLauncherUI(sortedCategories);
+ this._headerElement = document.createElement("h1");
+ this._headerElement.className = "no-audits";
+ this._headerElement.textContent = WebInspector.UIString("No audits to run");
+ this._contentElement.appendChild(this._headerElement);
}
WebInspector.AuditLauncherView.prototype = {
this._resetResourceCount();
},
+ addCategory: function(category)
+ {
+ if (!this._sortedCategories.length)
+ this._createLauncherUI();
+
+ var categoryElement = this._createCategoryElement(category.displayName, category.id);
+ category._checkboxElement = categoryElement.firstChild;
+ if (this._selectAllCheckboxElement.checked) {
+ category._checkboxElement.checked = true;
+ ++this._currentCategoriesCount;
+ }
+
+ function compareCategories(a, b)
+ {
+ var aTitle = a.displayName || "";
+ var bTitle = b.displayName || "";
+ return aTitle.localeCompare(bTitle);
+ }
+ var insertBefore = insertionIndexForObjectInListSortedByFunction(category, this._sortedCategories, compareCategories);
+ this._categoriesElement.insertBefore(categoryElement, this._categoriesElement.children[insertBefore]);
+ this._sortedCategories.splice(insertBefore, 0, category);
+ this._updateButton();
+ },
+
_setAuditRunning: function(auditRunning)
{
if (this._auditRunning === auditRunning)
{
var catIds = [];
var childNodes = this._categoriesElement.childNodes;
- for (var id in this._categoriesById) {
- if (this._categoriesById[id]._checkboxElement.checked)
- catIds.push(id);
+ for (var category = 0; category < this._sortedCategories.length; ++category) {
+ if (this._sortedCategories[category]._checkboxElement.checked)
+ catIds.push(this._sortedCategories[category].id);
}
+
this._setAuditRunning(true);
this._runnerCallback(catIds, this._auditPresentStateElement.checked, this._setAuditRunning.bind(this, false));
},
var childNodes = this._categoriesElement.childNodes;
for (var i = 0, length = childNodes.length; i < length; ++i)
childNodes[i].firstChild.checked = checkCategories;
- this._currentCategoriesCount = checkCategories ? this._totalCategoriesCount : 0;
+ this._currentCategoriesCount = checkCategories ? this._sortedCategories.length : 0;
this._updateButton();
},
_categoryClicked: function(event)
{
this._currentCategoriesCount += event.target.checked ? 1 : -1;
- this._selectAllCheckboxElement.checked = this._currentCategoriesCount === this._totalCategoriesCount;
+ this._selectAllCheckboxElement.checked = this._currentCategoriesCount === this._sortedCategories.length;
this._updateButton();
},
var element = document.createElement("input");
element.type = "checkbox";
+ element.addEventListener("click", this._boundCategoryClickListener, false);
labelElement.appendChild(element);
labelElement.appendChild(document.createTextNode(title));
return labelElement;
},
- _createLauncherUI: function(sortedCategories)
+ _createLauncherUI: function()
{
this._headerElement = document.createElement("h1");
this._headerElement.textContent = WebInspector.UIString("Select audits to run");
+
+ for (var child = 0; child < this._contentElement.children.length; ++child)
+ this._contentElement.removeChild(this._contentElement.children[child]);
+
this._contentElement.appendChild(this._headerElement);
function handleSelectAllClick(event)
this._categoriesElement.className = "audit-categories-container";
this._contentElement.appendChild(this._categoriesElement);
- var boundCategoryClickListener = this._categoryClicked.bind(this);
-
- for (var i = 0; i < sortedCategories.length; ++i) {
- categoryElement = this._createCategoryElement(sortedCategories[i].displayName, sortedCategories[i].id);
- categoryElement.firstChild.addEventListener("click", boundCategoryClickListener, false);
- sortedCategories[i]._checkboxElement = categoryElement.firstChild;
- this._categoriesElement.appendChild(categoryElement);
- }
-
- this._totalCategoriesCount = this._categoriesElement.childNodes.length;
this._currentCategoriesCount = 0;
var flexibleSpaceElement = document.createElement("div");
WebInspector.AuditCategoryResultPane.prototype = {
_appendResult: function(parentTreeElement, result)
{
- var title = result.value;
- if (result.violationCount)
- title = String.sprintf("%s (%d)", title, result.violationCount);
+ var title = "";
+
+ if (typeof result.value === "string") {
+ title = result.value;
+ if (result.violationCount)
+ title = String.sprintf("%s (%d)", title, result.violationCount);
+ }
var treeElement = new TreeElement(title, null, !!result.children);
parentTreeElement.appendChild(treeElement);
if (result.className)
treeElement.listItemElement.addStyleClass(result.className);
+ if (typeof result.value !== "string")
+ treeElement.listItemElement.appendChild(WebInspector.applyFormatters(result.value));
+
if (result.children) {
for (var i = 0; i < result.children.length; ++i)
this._appendResult(treeElement, result.children[i]);
{
WebInspector.Panel.call(this, "audits");
- this._constructCategories();
-
this.createSidebar();
this.auditsTreeElement = new WebInspector.SidebarSectionTreeElement("", {}, true);
this.sidebarTree.appendChild(this.auditsTreeElement);
this.viewsContainerElement.id = "audit-views";
this.element.appendChild(this.viewsContainerElement);
- this._launcherView = new WebInspector.AuditLauncherView(this.categoriesById, this.initiateAudit.bind(this));
+ this._constructCategories();
+
+ this._launcherView = new WebInspector.AuditLauncherView(this.initiateAudit.bind(this));
+ for (id in this.categoriesById)
+ this._launcherView.addCategory(this.categoriesById[id]);
}
WebInspector.AuditsPanel.prototype = {
this._launcherView.resourceFinished(resource);
},
+ addCategory: function(category)
+ {
+ this.categoriesById[category.id] = category;
+ this._launcherView.addCategory(category);
+ },
+
+ getCategory: function(id)
+ {
+ return this.categoriesById[id];
+ },
+
_constructCategories: function()
{
this._auditCategoriesById = {};
var category = categories[i];
var result = new WebInspector.AuditCategoryResult(category);
results.push(result);
- category.runRules(resources, ruleResultReadyCallback.bind(null, result));
+ category.run(resources, ruleResultReadyCallback.bind(null, result));
}
},
{
this.visibleView = this._launcherView;
},
-
+
get visibleView()
{
return this._visibleView;
this._rules.push(rule);
},
- runRules: function(resources, callback)
+ run: function(resources, callback)
{
this._ensureInitialized();
for (var i = 0; i < this._rules.length; ++i)
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-var injectedExtensionAPI = function(InjectedScriptHost, inspectedWindow, injectedScriptId)
+WebInspector.injectedExtensionAPI = function(InjectedScriptHost, inspectedWindow, injectedScriptId)
{
// Here and below, all constructors are private to API implementation.
// by Foo consutrctor to re-bind publicly exported members to an instance
// of Foo.
-function EventSinkImpl(type)
+function EventSinkImpl(type, customDispatch)
{
this._type = type;
this._listeners = [];
+ this._customDispatch = customDispatch;
}
EventSinkImpl.prototype = {
addListener: function(callback)
{
+ if (typeof callback != "function")
+ throw new "addListener: callback is not a function";
if (this._listeners.length === 0)
extensionServer.sendRequest({ command: "subscribe", type: this._type });
this._listeners.push(callback);
- extensionServer.registerHandler("notify-" + this._type, bind(this._fire, this));
+ extensionServer.registerHandler("notify-" + this._type, bind(this._dispatch, this));
},
removeListener: function(callback)
extensionServer.sendRequest({ command: "unsubscribe", type: this._type });
},
- _fire: function(request)
+ _fire: function()
{
var listeners = this._listeners.slice();
for (var i = 0; i < listeners.length; ++i)
- listeners[i].apply(null, request.arguments);
+ listeners[i].apply(null, arguments);
+ },
+
+ _dispatch: function(request)
+ {
+ if (this._customDispatch)
+ this._customDispatch.call(this, request);
+ else
+ this._fire.apply(this, request.arguments);
}
}
-function EventSink(type)
+function EventSink(type, customDispatch)
{
- var impl = new EventSinkImpl(type);
+ var impl = new EventSinkImpl(type, customDispatch);
this.addListener = bind(impl.addListener, impl);
this.removeListener = bind(impl.removeListener, impl);
}
function InspectorExtensionAPI()
{
+ this.audits = new Audits();
this.inspectedWindow = new InspectedWindow();
this.panels = new Panels();
this.resources = new Resources();
+
this.onReset = new EventSink("reset");
}
{
return panels[name];
}
-
+
for (var i = 0; i < wellKnownPanelNames.length; ++i) {
var name = wellKnownPanelNames[i];
panels[name] = new Panel(name);
id: id,
label: label,
url: expandURL(pageURL),
- icon: expandURL(iconURL)
+ icon: expandURL(iconURL)
};
extensionServer.sendRequest(request, callback && bind(callbackWrapper, this));
}
this.setExpanded = bind(impl.setExpanded, impl);
}
+function Audits()
+{
+}
+
+Audits.prototype = {
+ addCategory: function(displayName, ruleCount)
+ {
+ var id = "extension-audit-category-" + extensionServer.nextObjectId();
+ extensionServer.sendRequest({ command: "addAuditCategory", id: id, displayName: displayName, ruleCount: ruleCount });
+ return new AuditCategory(id);
+ }
+}
+
+function AuditCategory(id)
+{
+ function customDispatch(request)
+ {
+ var auditResult = new AuditResult(request.arguments[0]);
+ try {
+ this._fire(auditResult);
+ } catch (e) {
+ console.error("Uncaught exception in extension audit event handler: " + e);
+ auditResult.done();
+ }
+ }
+ var impl = new AuditCategoryImpl(id);
+ this.onAuditStarted = new EventSink("audit-started-" + id, customDispatch);
+}
+
+function AuditCategoryImpl(id)
+{
+ this._id = id;
+}
+
+function AuditResult(id)
+{
+ var impl = new AuditResultImpl(id);
+
+ this.addResult = bind(impl.addResult, impl);
+ this.createResult = bind(impl.createResult, impl);
+ this.done = bind(impl.done, impl);
+
+ var formatterTypes = [
+ "url",
+ "snippet",
+ "text"
+ ];
+ for (var i = 0; i < formatterTypes.length; ++i)
+ this[formatterTypes[i]] = bind(impl._nodeFactory, null, formatterTypes[i]);
+}
+
+AuditResult.prototype = {
+ get Severity()
+ {
+ return private.audits.Severity;
+ }
+}
+
+function AuditResultImpl(id)
+{
+ this._id = id;
+}
+
+AuditResultImpl.prototype = {
+ addResult: function(displayName, description, severity, details)
+ {
+ // shorthand for specifying details directly in addResult().
+ if (details && !(details instanceof AuditResultNode))
+ details = details instanceof Array ? this.createNode.apply(this, details) : this.createNode(details);
+
+ var request = {
+ command: "addAuditResult",
+ resultId: this._id,
+ displayName: displayName,
+ description: description,
+ severity: severity,
+ details: details
+ };
+ extensionServer.sendRequest(request);
+ },
+
+ createResult: function()
+ {
+ var node = new AuditResultNode();
+ node.contents = Array.prototype.slice.call(arguments);
+ return node;
+ },
+
+ done: function()
+ {
+ extensionServer.sendRequest({ command: "stopAuditCategoryRun", resultId: this._id });
+ },
+
+ _nodeFactory: function(type)
+ {
+ return {
+ type: type,
+ arguments: Array.prototype.slice.call(arguments, 1)
+ };
+ }
+}
+
+function AuditResultNode(contents)
+{
+ this.contents = contents;
+ this.children = [];
+ this.expanded = false;
+}
+
+AuditResultNode.prototype = {
+ addChild: function()
+ {
+ var node = AuditResultImpl.prototype.createResult.apply(null, arguments);
+ this.children.push(node);
+ return node;
+ }
+};
+
function InspectedWindow()
{
this.onLoaded = new EventSink("inspectedPageLoaded");
this._registerHandler("getResources", this._onGetResources.bind(this));
this._registerHandler("createPanel", this._onCreatePanel.bind(this));
this._registerHandler("createSidebarPane", this._onCreateSidebar.bind(this));
- this._registerHandler("log", this._onLog.bind(this));
+ this._registerHandler("log", this._onLog.bind(this));
this._registerHandler("evaluateOnInspectedPage", this._onEvaluateOnInspectedPage.bind(this));
this._registerHandler("setSidebarHeight", this._onSetSidebarHeight.bind(this));
this._registerHandler("setSidebarExpanded", this._onSetSidebarExpansion.bind(this));
+ this._registerHandler("addAuditCategory", this._onAddAuditCategory.bind(this));
+ this._registerHandler("addAuditResult", this._onAddAuditResult.bind(this));
+ this._registerHandler("stopAuditCategoryRun", this._onStopAuditCategoryRun.bind(this));
+
window.addEventListener("message", this._onWindowMessage.bind(this), false);
}
this._postNotification("reset");
},
+ startAuditRun: function(category, auditRun)
+ {
+ this._clientObjects[auditRun.id] = auditRun;
+ this._postNotification("audit-started-" + category.id, auditRun.id);
+ },
+
+ stopAuditRun: function(auditRun)
+ {
+ delete this._clientObjects[auditRun.id];
+ },
+
_convertResource: function(resource)
{
return {
return;
var message = {
command: "notify-" + type,
- arguments: Array.prototype.slice.call(arguments, 1)
+ arguments: Array.prototype.slice.call(arguments, 1)
};
for (var i = 0; i < subscribers.length; ++i)
subscribers[i].postMessage(message);
return response;
},
+ _onAddAuditCategory: function(request)
+ {
+ var category = new WebInspector.ExtensionAuditCategory(request.id, request.displayName, request.ruleCount);
+ if (WebInspector.panels.audits.getCategory(category.id))
+ return this._status.E_EXISTS(category.id);
+ this._clientObjects[request.id] = category;
+ WebInspector.panels.audits.addCategory(category);
+ },
+
+ _onAddAuditResult: function(request)
+ {
+ var auditResult = this._clientObjects[request.resultId];
+ if (!auditResult)
+ return this._status.E_NOTFOUND(request.resultId);
+ try {
+ auditResult.addResult(request.displayName, request.description, request.severity, request.details);
+ } catch (e) {
+ return e;
+ }
+ return this._status.OK();
+ },
+
+ _onStopAuditCategoryRun: function(request)
+ {
+ var auditRun = this._clientObjects[request.resultId];
+ if (!auditRun)
+ return this._status.E_NOTFOUND(request.resultId);
+ auditRun.cancel();
+ },
+
initExtensions: function()
{
InspectorExtensionRegistry.getExtensionsAsync();
_addExtensions: function(extensions)
{
- InspectorFrontendHost.setExtensionAPI("(" + injectedExtensionAPI.toString() + ")"); // See ExtensionAPI.js for details.
+ // See ExtensionAPI.js and ExtensionCommon.js for details.
+ InspectorFrontendHost.setExtensionAPI(this._buildExtensionAPIInjectedScript());
for (var i = 0; i < extensions.length; ++i) {
var extension = extensions[i];
try {
}
},
+ _buildExtensionAPIInjectedScript: function()
+ {
+ return "(function(){ " +
+ "var private = {};" +
+ "(" + WebInspector.commonExtensionSymbols.toString() + ")(private);" +
+ "(" + WebInspector.injectedExtensionAPI.toString() + ").apply(this, arguments);" +
+ "})";
+ },
+
_onWindowMessage: function(event)
{
if (event.data !== "registerExtension")
}
}
-WebInspector.ExtensionServer._statuses =
+WebInspector.ExtensionServer._statuses =
{
OK: "",
- E_NOTFOUND: "Object not found (%s)",
- E_NOTSUPPORTED: "Object does not support requested operation (%s)",
- E_EXISTS: "Object already exists (%s)"
+ E_EXISTS: "Object already exists: %s",
+ E_BADARG: "Invalid argument %s: %s",
+ E_BADARGTYPE: "Invalid type for argument %s: got %s, expected %s",
+ E_NOTFOUND: "Object not found: %s",
+ E_NOTSUPPORTED: "Object does not support requested operation: %s",
}
WebInspector.ExtensionStatus = function()
status.isError = true;
console.log("Extension server error: " + String.vsprintf(description, details));
}
- return status;
+ return status;
}
for (status in WebInspector.ExtensionServer._statuses)
this[status] = makeStatus.bind(null, status);
<file>AbstractTimelinePanel.js</file>
<file>ApplicationCacheItemsView.js</file>
<file>AuditCategories.js</file>
+ <file>AuditFormatters.js</file>
<file>AuditLauncherView.js</file>
<file>AuditResultView.js</file>
<file>AuditRules.js</file>
<file>ElementsTreeOutline.js</file>
<file>EventListenersSidebarPane.js</file>
<file>ExtensionAPI.js</file>
+ <file>ExtensionAuditCategory.js</file>
+ <file>ExtensionCommon.js</file>
<file>ExtensionPanel.js</file>
<file>ExtensionRegistryStub.js</file>
<file>ExtensionServer.js</file>
<script type="text/javascript" src="ProfilesPanel.js"></script>
<script type="text/javascript" src="ConsolePanel.js"></script>
<script type="text/javascript" src="ExtensionAPI.js"></script>
+ <script type="text/javascript" src="ExtensionAuditCategory.js"></script>
+ <script type="text/javascript" src="ExtensionCommon.js"></script>
<script type="text/javascript" src="ExtensionServer.js"></script>
<script type="text/javascript" src="ExtensionPanel.js"></script>
<script type="text/javascript" src="AuditsPanel.js"></script>
<script type="text/javascript" src="AuditLauncherView.js"></script>
<script type="text/javascript" src="AuditRules.js"></script>
<script type="text/javascript" src="AuditCategories.js"></script>
+ <script type="text/javascript" src="AuditFormatters.js"></script>
<script type="text/javascript" src="ResourceView.js"></script>
<script type="text/javascript" src="SourceFrame.js"></script>
<script type="text/javascript" src="DOMSyntaxHighlighter.js"></script>
function insertionIndexForObjectInListSortedByFunction(anObject, aList, aFunction)
{
- // indexOf returns (-lowerBound - 1). Taking (-result - 1) works out to lowerBound.
- return (-indexOfObjectInListSortedByFunction(anObject, aList, aFunction) - 1);
-}
-
-function indexOfObjectInListSortedByFunction(anObject, aList, aFunction)
-{
var first = 0;
var last = aList.length - 1;
var floor = Math.floor;
}
}
- // By returning 1 less than the negative lower search bound, we can reuse this function
- // for both indexOf and insertionIndexFor, with some simple arithmetic.
- return (-first - 1);
+ return first;
}
String.sprintf = function(format)